Hello. There is data in the database of this type:

_id | category | name 1 | cat1 | name2 2 | cat1 | name5 3 | cat3 | name1 4 | cat2 | name4 5 | cat1 | name3 6 | cat3 | name6 7 | cat1 | name9 

It is necessary to list this data through RecyclerView in the following form:

  cat1 1 | name2 2 | name5 5 | name3 7 | name9 cat2 4 | name4 cat3 3 | name1 6 | name6 

In other words, it is necessary to create a kind of header (separator / group) in the list from the category field, and after each header, output the data that corresponds to this header.

My fragment code is:

 import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.support.v4.app.Fragment; import android.os.Bundle; import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; public class Tab1 extends Fragment { private RecyclerView mRecyclerView; private RecyclerView.Adapter mAdapter; private RecyclerView.LayoutManager mLayoutManager; DB_Helper databaseHelper; SQLiteDatabase db; Cursor userCursor; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.my_tab1, container, false); databaseHelper = new DB_Helper(getContext()); db = databaseHelper.getReadableDatabase(); userCursor = db.rawQuery("SELECT * FROM `" + DB_Helper.DATABASE_TABLE + "` WHERE `_id` > '0' ORDER BY `category` ASC, `_id` DESC", null); ArrayList<HashMap<String, String>> myData = new ArrayList<>(); HashMap<String, String> mTab1; if (userCursor.moveToFirst()) { do { mTab1 = new HashMap<>(); mTab1.put("id", userCursor.getString(userCursor.getColumnIndex(DB_Helper.ID))); mTab1.put("cate", userCursor.getString(userCursor.getColumnIndex(DB_Helper.CATEGORY))); mTab1.put("name", userCursor.getString(userCursor.getColumnIndex(DB_Helper.NAME))); myData.add(mTab1); } while (userCursor.moveToNext()); } mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view); // если вы уверены, что изменения в контенте не изменят размер лайота, то передаём параметр true - это увеличивает производительность mRecyclerView.setHasFixedSize(true); // используем LinearLayoutManager для отображения как ListView mLayoutManager = new LinearLayoutManager(getActivity()); mRecyclerView.setLayoutManager(mLayoutManager); // добавляет горизонтальные полосочки между пунктами mRecyclerView.addItemDecoration(new DividerItemDecoration(mRecyclerView.getContext(), LinearLayoutManager.VERTICAL)); // создаём адаптер mAdapter = new RecyclerAdapter(myData); mRecyclerView.setAdapter(mAdapter); return rootView; } } 

My adapter code is RecyclerView:

 import android.content.Intent; import android.net.Uri; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; import java.util.ArrayList; import java.util.HashMap; public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> { private ArrayList<HashMap<String, String>> mDataset; public RecyclerAdapter(ArrayList<HashMap<String, String>> dataset) { mDataset = dataset; } @Override public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_tab1_item, parent, false); return new ViewHolder(v); } @Override public void onBindViewHolder(ViewHolder holder, int position) { HashMap<String, String> fast_parse = mDataset.get(position); String cate_str = fast_parse.get("cate"); String name_str = fast_parse.get("name"); holder.mMyListCateView.setText(cate_str); holder.mMyListNameView.setText(name_str); } @Override public int getItemCount() { return mDataset.size(); } public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { private TextView mMyListCateView, mMyListNameView; private LinearLayout holderLayout; public ViewHolder(View v) { super(v); mMyListCateView = (TextView) v.findViewById(R.id.myMyCate); mMyListNameView = (TextView) v.findViewById(R.id.myMyName); holderLayout = (LinearLayout) v.findViewById(R.id.myLinearLayout); holderLayout.setOnClickListener(this); } @Override public void onClick(View v) { int position = getAdapterPosition(); if (position != RecyclerView.NO_POSITION) { Intent intent = new Intent(v.getContext(), Squares_Dynamic_Base.class); HashMap<String, String> fast_parse = mDataset.get(position); intent.putExtra("id", fast_parse.get("id")); v.getContext().startActivity(intent); } } } } 

From the examples, here and here I realized that it is necessary to use getItemViewType and use it to load different Layout for the heading of the items and for the items themselves (this is ideal because the idea of ​​the header will be different from the design of the items in the list). But in many other examples, lists are used in which the data for the headings have been initially added, and my headings should be formed from what is. Please tell the code how to implement the desired.

PS Various decorations and beautiful effects are NOT necessary. I need the most simple and working code.

    4 answers 4

    Here there is a library, there they have an example with source codes.

    RecyclerView

    method of generating items. As you can see, I have them different. I have HeaderModel_Cvodka and ContentModel_Cvodka .

     @NonNull private ArrayList<ItemModel> getItems() { final ArrayList<ItemModel> items = new ArrayList<>(); DannieClanNew dannieClan; if(locationTanki.getDannieClanNew() != null) dannieClan = locationTanki.getDannieClanNew(); else dannieClan = null; items.add(new HeaderModel_Cvodka(Integer.toString(locationTanki.getPersonaly_dannie().getGlobal_rating()), "Личный рейтинг", "Изображение", locationTanki.getPersonaly_dannie().getNickname(), dannieClan)); // for (int i = 0; i < 5; i++) { // for (int j = 0; j < 8; j++) { items.add(new ContentModel_Cvodka(TITLES2.get(j),TITLES2_1[j],IMAGES2[j])); // } } }` 

    In the example, you will see this line mRecyclerViewAdapter.setItems(getItems()); where RececlerView declared

    • thanks for the answer. I reviewed a lot of examples and libraries. They are all too cool for me. I would like something very simple to just display a list without collapsing groups, without various effects. Here's just a headline and paragraphs ... - Gamlet
    • why don't you use then the usual RecyclerView with two objects. And just depending on what that output. Now I’ll look like I have an example - Vitaly Robinovsky
    • Look here please. I am inexperienced in Android programming, so similar examples would help me a lot. - Gamlet
    • github.com/vivchar/RendererRecyclerViewAdapter , it has an example. For now, look here, and I’ll find mine , how I use it - Vitaly Robinovsky
    • Try to analyze this example. My example is too big and complicated - Vitaly Robinovsky

    To create elements of different types, you just need to use different ViewHolder , no one forbids to make them of different types, moreover there is a getItemViewType() method, the type is set by int constants. In this scenario, data can be stored in TreeMap<Key,List<YourItem>> or SparseArray (which is preferable for the Android platform), in this case the getItemCount () method should return the sum of the sizes of all sheets + 1 header for each sheet, and in the getItemViewType() method getItemViewType() you need to write the logic for calculating the type of the element (to catch the moment when you need to return the header type). Well, that's all.

    • I have very little experience. I kind of understand the logic. But I do not know how to implement it in practice. Roughly speaking, now I do it by typing and from examples on the Internet, I try to make everything into one. If it's not difficult for you, could you show what to insert in the code? It seems to me that it is not entirely difficult, especially since I do not need various kinds of effects. - Gamlet

    The most simple and clumsy solution in my opinion

    At the top, you add a separator to the element markup, for example, it will contain only TextView

    In the adapter, you check if the previous element differs in category from the current one, then you show the separator, otherwise you hide it

    This will be the easiest option.

    Little year

    List Item Layout

     LinearLayout orientation: vertical TextView id: category TextView id: name 

    In the adapter itself, in the method where you display information in ViewHolder, something like this

     viewHolder.category.setText(list.get(position).category) if (position == 0 || !list.get(position).category.equals(list.get(position-1)) { viewHolder.category.setVisibility(VISIBLE) } else { viewHolder.category.setVisibility(GONE) } 

      In general, I sat down, I thought how to implement the necessary and came to such a decision. In the first file, just took a piece:

       mTab1 = new HashMap<>(); mTab1.put("id", userCursor.getString(userCursor.getColumnIndex(DB_Helper.ID))); mTab1.put("cate", userCursor.getString(userCursor.getColumnIndex(DB_Helper.CATEGORY))); mTab1.put("name", userCursor.getString(userCursor.getColumnIndex(DB_Helper.NAME))); myData.add(mTab1); 

      and replaced it with this:

       TYPE_CATE = userCursor.getString(userCursor.getColumnIndex(DB_Helper.CATEGORY)); if (TYPE_CATE.equals(TYPE_NEW)) { mTab1.put("id", userCursor.getString(userCursor.getColumnIndex(DB_Helper.ID))); mTab1.put("cate", userCursor.getString(userCursor.getColumnIndex(DB_Helper.CATEGORY))); mTab1.put("name", userCursor.getString(userCursor.getColumnIndex(DB_Helper.NAME))); mTab1.put("rang", "0"); } else { mTab1.put("cate", userCursor.getString(userCursor.getColumnIndex(DB_Helper.CATEGORY))); mTab1.put("rang", "1"); TYPE_NEW = userCursor.getString(userCursor.getColumnIndex(DB_Helper.CATEGORY)); userCursor.moveToPrevious(); } 

      at the same time, where we define variables, we need to add:

       public String TYPE_CATE = ""; public String TYPE_NEW = ""; 

      Thus, the list was formed exactly in the form in which it was needed. Those. one line with a title and a note that this is the title. And then all the items that correspond to this title, etc.

      Then the data is transferred to the adapter, which I easily and simply rewrote according to this video (watch approximately from the 6th minute).

      I do not know, of course, how right it is. Perhaps the implementation is very crooked and logically incorrect, but the result of the work pleases. Everything works exactly as it should))