Divide elements on groups in RecyclerView or Grouping Recyclerview items ,say by date
Here is a solution i came by with the aid of alot research over the net and this blog link as well Kartikey Kuswhaha so its not all my credit but i just want to give more clarity to it.
below is the code:
create the following files:PojoOfJsonArray,MainActivity, ListItem ,GeneralItem ,DateItem , Adapter
PojoOfJsonArray.java -this file wil represent your POJO class or whatever pojo you got going on in your app so:
public class PojoOfJsonArray {
public PojoOfJsonArray(String name, String date) {
this.name = name;
this.date = date;
}
private String name,date;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
MainActivity.java this is the activity that you will use to implement you recyclerview :
public class MainActivity extends AppCompatActivity {
private List<PojoOfJsonArray> myOptions = new ArrayList<>();
List<ListItem> consolidatedList = new ArrayList<>();
private RecyclerView mRecyclerView;
private Adapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mRecyclerView.setHasFixedSize(true);
myOptions.add(new PojoOfJsonArray("name 1", "2016-06-21"));
myOptions.add(new PojoOfJsonArray("name 2", "2016-06-05"));
myOptions.add(new PojoOfJsonArray("name 2", "2016-06-05"));
myOptions.add(new PojoOfJsonArray("name 3", "2016-05-17"));
myOptions.add(new PojoOfJsonArray("name 3", "2016-05-17"));
myOptions.add(new PojoOfJsonArray("name 3", "2016-05-17"));
myOptions.add(new PojoOfJsonArray("name 3", "2016-05-17"));
myOptions.add(new PojoOfJsonArray("name 2", "2016-06-05"));
myOptions.add(new PojoOfJsonArray("name 3", "2016-05-17"));
HashMap<String, List<PojoOfJsonArray>> groupedHashMap = groupDataIntoHashMap(myOptions);
for (String date : groupedHashMap.keySet()) {
DateItem dateItem = new DateItem();
dateItem.setDate(date);
consolidatedList.add(dateItem);
for (PojoOfJsonArray pojoOfJsonArray : groupedHashMap.get(date)) {
GeneralItem generalItem = new GeneralItem();
generalItem.setPojoOfJsonArray(pojoOfJsonArray);//setBookingDataTabs(bookingDataTabs);
consolidatedList.add(generalItem);
}
}
adapter = new Adapter(this, consolidatedList);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(adapter);
}
private HashMap<String, List<PojoOfJsonArray>> groupDataIntoHashMap(List<PojoOfJsonArray> listOfPojosOfJsonArray) {
HashMap<String, List<PojoOfJsonArray>> groupedHashMap = new HashMap<>();
for (PojoOfJsonArray pojoOfJsonArray : listOfPojosOfJsonArray) {
String hashMapKey = pojoOfJsonArray.getDate();
if (groupedHashMap.containsKey(hashMapKey)) {
// The key is already in the HashMap; add the pojo object
// against the existing key.
groupedHashMap.get(hashMapKey).add(pojoOfJsonArray);
} else {
// The key is not there in the HashMap; create a new key-value pair
List<PojoOfJsonArray> list = new ArrayList<>();
list.add(pojoOfJsonArray);
groupedHashMap.put(hashMapKey, list);
}
}
return groupedHashMap;
}
}
the myOptions is where one would use to feed your data into.
ListItem.java
public abstract class ListItem {
public static final int TYPE_DATE = 0;
public static final int TYPE_GENERAL = 1;
abstract public int getType();
}
GeneralItem.java
public class GeneralItem extends ListItem {
private PojoOfJsonArray pojoOfJsonArray;
public PojoOfJsonArray getPojoOfJsonArray() {
return pojoOfJsonArray;
}
public void setPojoOfJsonArray(PojoOfJsonArray pojoOfJsonArray) {
this.pojoOfJsonArray = pojoOfJsonArray;
}
@Override
public int getType() {
return TYPE_GENERAL;
}
}
DateItem.java
public class DateItem extends ListItem {
private String date;
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
@Override
public int getType() {
return TYPE_DATE;
}
}
Adapter.java this adapter is for the recyclerview if your not well informed on how to make simple sectioned recyclerview then i suggest you read on those and be good in the area because this is abit more tricky anyways:
public class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
List<ListItem> consolidatedList = new ArrayList<>();
public Adapter(Context context, List<ListItem> consolidatedList) {
this.consolidatedList = consolidatedList;
this.mContext = context;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case ListItem.TYPE_GENERAL:
View v1 = inflater.inflate(R.layout.items, parent,
false);
viewHolder = new GeneralViewHolder(v1);
break;
case ListItem.TYPE_DATE:
View v2 = inflater.inflate(R.layout.itemsh, parent, false);
viewHolder = new DateViewHolder(v2);
break;
}
return viewHolder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()) {
case ListItem.TYPE_GENERAL:
GeneralItem generalItem = (GeneralItem) consolidatedList.get(position);
GeneralViewHolder generalViewHolder= (GeneralViewHolder) viewHolder;
generalViewHolder.txtTitle.setText(generalItem.getPojoOfJsonArray().getName());
break;
case ListItem.TYPE_DATE:
DateItem dateItem = (DateItem) consolidatedList.get(position);
DateViewHolder dateViewHolder = (DateViewHolder) viewHolder;
dateViewHolder.txtTitle.setText(dateItem.getDate());
// Populate date item data here
break;
}
}
// ViewHolder for date row item
class DateViewHolder extends RecyclerView.ViewHolder {
protected TextView txtTitle;
public DateViewHolder(View v) {
super(v);
this.txtTitle = (TextView) v.findViewById(R.id.txt);
}
}
// View holder for general row item
class GeneralViewHolder extends RecyclerView.ViewHolder {
protected TextView txtTitle;
public GeneralViewHolder(View v) {
super(v);
this.txtTitle = (TextView) v.findViewById(R.id.txt);
}
}
@Override
public int getItemViewType(int position) {
return consolidatedList.get(position).getType();
}
@Override
public int getItemCount() {
return consolidatedList != null ? consolidatedList.size() : 0;
}
}
and this has two layout being used . thus all
Divide elements on groups in RecyclerView
For example you can:
Use a
TreeMap<Date,List<Event>>
for splitting elements by date. This will be a collection for keeping your business objects. Of course if you already have a similar structure you can keep it. It's just important to have something for easily building list of items for populating UI with right elements order.Define a dedicated abstract type for
List
items (e.g.ListItem
) to wrap your business objects. Its implementation could be something like this:public abstract class ListItem {
public static final int TYPE_HEADER = 0;
public static final int TYPE_EVENT = 1;
abstract public int getType();
}Define a class for each of your List element type (here I added just two types but you can use many as you need):
public class HeaderItem extends ListItem {
private Date date;
// here getters and setters
// for title and so on, built
// using date
@Override
public int getType() {
return TYPE_HEADER;
}
}
public class EventItem extends ListItem {
private Event event;
// here getters and setters
// for title and so on, built
// using event
@Override
public int getType() {
return TYPE_EVENT;
}
}Create a List as follows (where mEventsMap is map build at point 1):
List<ListItem> mItems;
// ...
mItems = new ArrayList<>();
for (Date date : mEventsMap.keySet()) {
HeaderItem header = new HeaderItem();
header.setDate(date);
mItems.add(header);
for (Event event : mEventsMap.get(date)) {
EventItem item = new EventItem();
item.setEvent(event);
mItems.add(item);
}
}Define an adapter for your
RecyclerView
, working onList
defined at point 4. Here what is important is to overridegetItemViewType
method as follows:@Override
public int getItemViewType(int position) {
return mItems.get(position).getType();
}Then you need to have two layouts and ViewHolder for header and event items. Adapter methods should take care of this accordingly:
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ListItem.TYPE_HEADER) {
View itemView = mLayoutInflater.inflate(R.layout.view_list_item_header, parent, false);
return new HeaderViewHolder(itemView);
} else {
View itemView = mLayoutInflater.inflate(R.layout.view_list_item_event, parent, false);
return new EventViewHolder(itemView);
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) {
int type = getItemViewType(position);
if (type == ListItem.TYPE_HEADER) {
HeaderItem header = (HeaderItem) mItems.get(position);
HeaderViewHolder holder = (HeaderViewHolder) viewHolder;
// your logic here
} else {
EventItem event = (EventItem) mItems.get(position);
EventViewHolder holder = (EventViewHolder) viewHolder;
// your logic here
}
}
Here it is a repository on GitHub providing an implementation of the approach explained above.
Grouping recycler-view items by date?
Sounds like you just want to have two ViewTypes like explained here
You might also want to take a look at this library and if you want it to be expandable and sexy you could take a look at Advanced RecyclerView library.
How to add dividers, spacers, or header with text to a recylerview
I took a bit of time but I was able to do it.
This is the output
1) MainActivity.java
public class MainActivity extends AppCompatActivity implements OnStartDragListener{
RecyclerView recyclerView;
private ItemTouchHelper mItemTouchHelper;
private List<Item> itemList = new ArrayList<>();
private RecyclerViewAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mAdapter = new RecyclerViewAdapter(itemList, MainActivity.this);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addItemDecoration(new SeparationDecorator());
recyclerView.setAdapter(mAdapter);
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(mAdapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(recyclerView);
prepareItemData();
}
private void prepareItemData() {
Item item = new Item("Apple Pay");
itemList.add(item);
item = new Item("1706-XXXX-XXXX-1112");
itemList.add(item);
item = new Item("Google pay");
itemList.add(item);
mAdapter.notifyDataSetChanged();
}
@Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
mItemTouchHelper.startDrag(viewHolder);
}
}
2) OnStartDragListener.java
public interface OnStartDragListener {
void onStartDrag(RecyclerView.ViewHolder viewHolder);
}
3) SimpleItemTouchHelperCallback.java
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final ItemTouchHelperAdapter mAdapter;
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
mAdapter = adapter;
}
@Override
public boolean isLongPressDragEnabled() {
return true;
}
@Override
public boolean isItemViewSwipeEnabled() {
return false; // make this true to enable swipe to delete
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
}
4) ItemTouchHelperAdapter.java
public interface ItemTouchHelperAdapter {
void onItemMove(int fromPosition, int toPosition);
void onItemDismiss(int position);
}
5) SeparationDecorator.java
public class SeparationDecorator extends RecyclerView.ItemDecoration {
private int textSize = 50;
private int groupSpacing = 100;
private Paint paint = new Paint();
{
paint.setTextSize(textSize);
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(view);
if (position == 0) {
c.drawText("DEFAULT", view.getLeft(),
view.getTop() - groupSpacing / 2 + textSize / 3, paint);
} else if(position == 1) {
c.drawText("OTHER", view.getLeft(),
view.getTop() - groupSpacing / 2 + textSize / 3, paint);
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) == 0 || parent.getChildAdapterPosition(view) == 1) {
outRect.set(0, groupSpacing, 0, 0);
}
}
}
6) RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> implements ItemTouchHelperAdapter{
private List<Item> itemList;
private Context context;
@Override
public void onItemMove(int fromPosition, int toPosition) {
Item prev = itemList.remove(fromPosition);
itemList.add(toPosition > fromPosition ? toPosition - 1 : toPosition, prev);
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onItemDismiss(int position) {
itemList.remove(position);
notifyItemRemoved(position);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
}
}
public RecyclerViewAdapter(List<Item> itemList, Context context) {
this.itemList = itemList;
this.context = context;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.view_item, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Item movie = itemList.get(position);
holder.title.setText(movie.getTitle());
}
@Override
public int getItemCount() {
return itemList.size();
}
}
7) Item.java
public class Item {
private String title;
public Item(String title) {
this.title = title;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
This is it. This was able to solve your problem.
I am not able to explain you the complete code, I will take some time in future definitely and explain it.
Not able to parse JSON into a recyclerview
You are getting data in an asynchronous way but you are setting data in recyclerview as a synchronous way that's why the list is empty. Follow the given strategy:
Replace adapter.notifyDataSetChanged() to update() method and remove all code after parseJSON(); method.
private void update(){
HashMap<String, List<StreamItem>> groupedHashMap = groupDataIntoHashMap(myOptions);
for (String date : groupedHashMap.keySet()) {
HeaderItem dateItem = new HeaderItem();
dateItem.setDate(date);
consolidatedList.add(dateItem);
for (StreamItem pojoOfJsonArray : groupedHashMap.get(date)) {
EventItem generalItem = new EventItem();
generalItem.setStreamItem(pojoOfJsonArray);//setBookingDataTabs(bookingDataTabs);
consolidatedList.add(generalItem);
}
}
adapter = new StreamArrayAdapter(this, consolidatedList);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(adapter);}
How to split Recycler view into 2 divisions based on type from a JSON file in Kotlin - android studio
I ended up filtering through my json file and splitting it into 2 lists. One that contains all the card types, another for all the bank types. Then passing each through their individual recycler.
val cardData: MutableList <Data> = mutableListOf<Data>()
val bankData: MutableList <Data> = mutableListOf<Data>()
for(i in data) {
if (i.account_type.equals("card")){
cardData.add(i)
}
}
for(i in data) {
if (i.account_type.equals("bank")){
bankData.add(i)
}
}
To clarify, data is a list that uses the helper class Data using Gson, assign the json file to it in my main activity.
Related Topics
Sorting a List of Map<String, String>
Android: How to Hide Actionbar on Certain Activities
Changing Openssl Library in Android App for Httpclient
No Resource Identifier Found for Attribute 'Layout_Behavior' in Package
Version Control for One-Man Project Using Eclipse
How to Escape Apostrophe or Quotes on a Jsp (Used by JavaScript)
How to Pass an Arraylist to a Varargs Method Parameter
String-Date Conversion with Nanoseconds
Why Do Variable Names Often Start with the Letter 'M'
Xmpp with Java Asmack Library Supporting X-Facebook-Platform
Double Tap: Zoom on Android Mapview
How to Programmatically Add Views and Constraints to a Constraintlayout
What Is the Use of Basecolumns in Android
What Is the Use of Memoryfile in Android
How Does One Configure Rjava on Osx to Select the Right Jvm -- .Jinit() Failing