How to add 2 Section Headers in Recycler View? - android

I want to to add 2 Section Headers in Recycler View..
I want to develop Header inside a Header.
I dont want to use Expandable view.I need it in Scroll-able view.
I want to show Tour Name as 1st Header.
Under that i want to show Location as 2nd Header

You can achieve this by using different view types in RecyclerView.
Firstly, You need to pass a list of objects to your recycler view adapter that specify whether the data should be used as a section header or not.
Here's an example of that data class.
// In a fuller example, this would probably hold more data than just strings.
public class SectionOrRow {
private String row;
private String section;
private boolean isRow;
public static SectionOrRow createRow(String row) {
SectionOrRow ret = new SectionOrRow();
ret.row = row;
ret.isRow = true;
return ret;
}
public static SectionOrRow createSection(String section) {
SectionOrRow ret = new SectionOrRow();
ret.section = section;
ret.isRow = false;
return ret;
}
public String getRow() {
return row;
}
public String getSection() {
return section;
}
public boolean isRow() {
return isRow;
}
}
Create data list of these objects with SectionOrRow.createRow("a normal row") or SectionOrRow.createSection("a section header"), and the isRow boolean is set accordingly.
Define the getItemViewType method in adapter, which tells recycler view there will be two types, a row type and a section type, and we'll specify which position these are in by looking at the isRow boolean in above data object.
Here's an example of Adapter class.
public class SectionRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final int VIEW_TYPE_SECTION = 0;
public static final int VIEW_TYPE_ITEM = 1;
private List<SectionOrRow> mData;
public MyRecycler(List<SectionOrRow> data) {
mData = data;
}
public class RowViewHolder extends RecyclerView.ViewHolder{
private TextView textView;
public RowViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(android.R.id.text1);
}
}
public class SectionViewHolder extends RecyclerView.ViewHolder{
private TextView textView;
public SectionViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(android.R.id.text1);
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType==VIEW_TYPE_SECTION) {
View v = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
v.findViewById(android.R.id.text1).setBackgroundColor(Color.BLUE);
return new SectionViewHolder(v);
} else {
View v = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
return new RowViewHolder(v);
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
SectionOrRow item = mData.get(position);
if(item.isRow()) {
RowViewHolder h = (RowViewHolder) holder;
h.textView.setText(item.getRow());
} else {
SectionViewHolder h = (SectionViewHolder) holder;
h.textView.setText(item.getSection());
}
}
#Override
public int getItemViewType(int position) {
super.getItemViewType(position);
SectionOrRow item = mData.get(position);
if(!item.isRow()) {
return VIEW_TYPE_SECTION;
} else {
return VIEW_TYPE_ITEM;
}
}
#Override
public int getItemCount() {
return mData.size();
}
}
In this example, It's just using the standard simple_list_item_1 for both but with a blue text background for the section. You can change raw and section layouts as per your requirement.

You have to pass a list of objects to your adapter that specify whether the data is getting inserted of not.
Add a debugger and test it.

Related

Two viewholders in an adapter

I parsed XML and got datas from two APIs.
arrival is for the bus stops and position is for the position of running buses.
The problem is views are added as many as the number of buses(i.e. positionInfoArrayListSize).
(there are seven buses in the picture.)
Are the views made as many as the number of returned getItemCount()?
How can I fix this?
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int VIEW_TYPE_ARRIVAL = 0;
private static final int VIEW_TYPE_POSITION = 1;
private ArrayList<ArrivalInfo> arrivalInfoArrayList;
private ArrayList<PositionInfo> positionInfoArrayList;
private int arrivalInfoArrayListSize;
private int positionInfoArrayListSize;
public MyAdapter(ArrayList<ArrivalInfo> arrivalInfoArrayList, ArrayList<PositionInfo> positionInfoArrayList) {
this.arrivalInfoArrayList = arrivalInfoArrayList;
this.positionInfoArrayList = positionInfoArrayList;
arrivalInfoArrayListSize = arrivalInfoArrayList.size();
positionInfoArrayListSize = positionInfoArrayList.size();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.test2, parent, false);
if (viewType == VIEW_TYPE_ARRIVAL) {
return new ArrivalViewHolder(view);
}
if (viewType == VIEW_TYPE_POSITION) {
return new PositionViewHolder(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof ArrivalViewHolder) {
((ArrivalViewHolder) holder).bind(arrivalInfoArrayList.get(position));
}
if (holder instanceof PositionViewHolder) {
((PositionViewHolder)holder).bind(positionInfoArrayList.get(position - arrivalInfoArrayListSize));
}
}
#Override
public int getItemCount() {
return arrivalInfoArrayListSize + positionInfoArrayListSize;
}
#Override
public int getItemViewType(int position){
if(position < arrivalInfoArrayListSize){
return VIEW_TYPE_ARRIVAL;
}
if(position - arrivalInfoArrayListSize < positionInfoArrayListSize){
return VIEW_TYPE_POSITION;
}
return -1;
}
public class ArrivalViewHolder extends RecyclerView.ViewHolder {
private TextView tv_stNm;
private TextView tv_arsId;
public ArrivalViewHolder(View v) {
super(v);
tv_stNm = v.findViewById(R.id.stNm);
tv_arsId = v.findViewById(R.id.arsId);
}
public void bind(ArrivalInfo arrivalInfo) {
tv_arsId.setText(arrivalInfo.getArsId());
tv_stNm.setText(arrivalInfo.getStNm());
}
}
public class PositionViewHolder extends RecyclerView.ViewHolder {
private ImageView iv_bus1;
private ImageView iv_bus2;
public PositionViewHolder(View v) {
super(v);
iv_bus1 = v.findViewById(R.id.busImage1);
iv_bus2 = v.findViewById(R.id.busImage2);
}
public void bind(PositionInfo positionInfo) {
if(positionInfo.getStopFlag().equals("1")) iv_bus1.setVisibility(positionInfo.getSectOrd());
if(positionInfo.getStopFlag().equals("0")) iv_bus2.setVisibility(positionInfo.getSectOrd());
}
}
}
Number of view recycler view create is
the number you return in getItemCount (ignoring the recycling process)
what i understand from your problem that you want to do something like this
bus arrival info
position info
position info
bus arrival info
...etc
list will be mixed up of arrival and position info so you can't show arrival info then position info.
if what i understood is right.then i recommend you to use abstract class Info which will implment comparable so you can sort array list and have method gettype
and in adapter you have arraylist of your abstract class and you can use it in a proper way,if you can add you code to github or any open source platform ,i could help you further

add header by list category in recyclerview

I am building a sample transaction app with the ability to categorize the list item based on its category. e.g. user can add a new list item with category sport and i would like to have a sport as header in the recyclerview and later on if item with category movie added, then the new item will be under movie.
I understand that i have to provide the itemViewType in my adapter class. and then i will have a List<txn> that mixed with different view types.
my current approach in following block is using Map<String, List<Item>> to keep track of each new item for particular category. But I was told one of my colleague that there is more efficient way to handle this.
But what kind of data structures I should use so that I can support
user can add any new category.
when user use the existing category,
then it should be add into the particular section in the recycler
view only?
public class txnAdapter extends
RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final int TRANSCATION_TYPE = 1;
public static final int HEAD_TYPE = 2;
private List<Txn> txns;
private List<Object> items;
private Map<String, List<Txn>> map;
public txnAdapter() {
map = new HashMap<>();
txns = new ArrayList<>();
items = new ArrayList<>();
}
public void setTxns(List<Txn> txns) {
//make a copy
this.txns.addAll(txns);
addToMap(txns);
resetList(this.txns);
}
public void addTxn(Txn txn) {
//filter by type and insert.
//find the index of category in list and
List<Txn> list = new ArrayList<>();
list.add(txn);
addToMap(list);
resetList(this.txns);
}
void addToMap(List<Txn> txns){
for(Txn t: txns){
if(!map.containsKey(t.getCategory())){
map.put(t.getCategory(), new ArrayList<Txn>());
}
List<Txn> list = map.get(t.getCategory());
list.add(t);
map.put(t.getCategory(), list);
}
}
void resetList(List<Txn> txns) {
items.clear();
for(Map.Entry<String, List<Txn>> e: map.entrySet()){
if(!items.contains(e.getKey())){
items.add(e.getKey());
}
items.addAll(e.getValue());
}
notifyDataSetChanged();
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//inflat the layout
View itemView = null;
if (viewType == HEAD_TYPE) {
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_header, parent, false);
return new headerViewHolder(itemView);
} else if (viewType == TRANSCATION_TYPE) {
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
return new transcationViewHolder(itemView);
}
return new transcationViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
Object cur = this.items.get(position);
if (holder instanceof headerViewHolder) {
((headerViewHolder) holder).gategoryTV.setText((String) cur);
} else if (holder instanceof transcationViewHolder) {
((transcationViewHolder) holder).titleTV.setText(((Txn) cur).getTitle());
((transcationViewHolder) holder).dateTV.setText(((Txn) cur).getDate());
((transcationViewHolder) holder).amountTV.setText(((Txn) cur).getAmount() + "");
}
}
#Override
public int getItemCount() {
return items == null ? 0 : items.size();
}
#Override
public int getItemViewType(int position) {
if (items.get(position) instanceof String) {
//this is header
return HEAD_TYPE;
} else if (items.get(position) instanceof Txn) {
return TRANSCATION_TYPE;
}
return -1;
}
private class transcationViewHolder extends RecyclerView.ViewHolder {
private TextView titleTV;
private TextView dateTV;
private TextView amountTV;
public transcationViewHolder(#NonNull View itemView) {
super(itemView);
this.titleTV = itemView.findViewById(R.id.title);
this.dateTV = itemView.findViewById(R.id.date);
this.amountTV = itemView.findViewById(R.id.amount);
}
}
private class headerViewHolder extends RecyclerView.ViewHolder {
private TextView gategoryTV;
public headerViewHolder(#NonNull View itemView) {
super(itemView);
this.gategoryTV = itemView.findViewById(R.id.category);
}
}
Try this library I think it should full fill your requirements,
https://github.com/luizgrp/SectionedRecyclerViewAdapter
you have to do some customisation there it surely work.

Unable to add second child in recyclerview

Unable to add second child in Recyclerview I am passing two different arrays to RecyclerAdapter to display two child layout with different data and views.Is there any solution to add different child layout using same header layout.I added horizontal Recyclerview in vertical Recyclerview and I want to display details like I attached the image
private void setupRecyclerView(RecyclerView recyclerView) {
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
RecyclerAdapter recyclerAdapter = new RecyclerAdapter();
int[] images = new int[]{
R.drawable.finance,
R.drawable.business,
R.drawable.financejob,
R.drawable.ecomchallenges
};
ArrayList<ChildView> childViews = new ArrayList<>();
childViews.add(new ChildView(images[0], "The \"Best\" Startup Pitch Deck - How To Raise Venture Capital", "$100"));
childViews.add(new ChildView(images[1], "An Entire MBA in 1 Course:Award Winning Business School Prof", "$100"));
childViews.add(new ChildView(images[2], "What Finance Job is for You? Explanation of 14 Finance Roles", "$100"));
childViews.add(new ChildView(images[3], "Learn To Build Beautiful HTML5 And CSS3 Websites In 1 Month", "$100"));
int[] courseImage = new int[] {
R.drawable.php,
R.drawable.development,
R.drawable.web,
R.drawable.java
};
ArrayList<CourseByType> courseByTypes = new ArrayList<>();
courseByTypes.add(new CourseByType("Technology", courseImage[0]));
courseByTypes.add(new CourseByType("Business", courseImage[1]));
courseByTypes.add(new CourseByType("Photography", courseImage[2]));
courseByTypes.add(new CourseByType("Development", courseImage[3]));
Log.d("","Above adapter");
recyclerAdapter.addItem(new GroupView("Business", childViews));
Log.d("","Below Child");
recyclerAdapter.addCourseByType(new CourseByHeader("Technology", courseByTypes));
Log.d("","Below Course");
recyclerView.setAdapter(recyclerAdapter);
}
This is the main fragment where I set the values to two different
arraylist ArrayList<ChildView> childViews = new ArrayList<>()
and
ArrayList<CourseByType> courseByTypes = new ArrayList<>()
Values of child views are passing properly but CourseByType values are not passing.This is the adapter class for this fragment class.
RecyclerAdapter.java
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
ArrayList<PassValues> containerArrayList;
ArrayList<GroupView> groupViews;
ArrayList<CourseByHeader>courseByHeaders;
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
View view = LayoutInflater.from(context).inflate(R.layout.group_title, parent, false);
return new ViewHolder(view);
}
public RecyclerAdapter(){
containerArrayList = new ArrayList<>();
groupViews = new ArrayList<>();
courseByHeaders = new ArrayList<>();
}
public void addContainer(PassValues container){
containerArrayList.add(container);
}
public void addItem(GroupView groupView){
Log.d("","Inside Group method");
groupViews.add(groupView);
}
public void addCourseByType(CourseByHeader courseByHeader){
Log.d("","Inside Course method");
courseByHeaders.add(courseByHeader);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Log.d("", "Pass Values out of IF" + position);
ChildViewAdapter childViewAdapter = new ChildViewAdapter();
if(position == 0){
GroupView groupView = groupViews.get(position);
holder.title.setText(groupView.getTitle());
Log.d("", "Passing Values" + groupView.getTitle());
holder.recyclerView.setLayoutManager(new LinearLayoutManager(holder.recyclerView.getContext(), LinearLayoutManager.HORIZONTAL, false));
holder.recyclerView.setOnFlingListener(null);
childViewAdapter.addChild(groupView.getChildViewList());
holder.recyclerView.setAdapter(childViewAdapter);
}
if (position == 1) {
CourseByHeader courseByHeader = courseByHeaders.get(position);
holder.title.setText(courseByHeader.getTitle());
Log.d("", "Passing Values" + courseByHeader.getTitle());
holder.recyclerView.setLayoutManager(new LinearLayoutManager(holder.recyclerView.getContext(), LinearLayoutManager.HORIZONTAL, false));
holder.recyclerView.setOnFlingListener(null);
childViewAdapter.addCourse(courseByHeader.getCourseByTypes());
holder.recyclerView.setAdapter(childViewAdapter);
}
}
#Override
public int getItemCount() {
if(getItemViewType(0) == TYPE_HEADER)
return groupViews.size() ;
if (getItemViewType(1) == TYPE_ITEM)
return courseByHeaders.size();
else return -1;
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView title;
RecyclerView recyclerView;
public ViewHolder(View itemView) {
super(itemView);
title = (TextView)itemView.findViewById(R.id.course_title);
recyclerView = (RecyclerView)itemView.findViewById(R.id.group_recycler);
}
}
}
This RecyclerAdapter contains one RecyclerView in that first row has one image and 3 textviews and 2nd row has 1 ImageView and 1 TextView. At position first,one image and 3 textviews are shown but it's not going on 2nd view
This is the view I getting after run on emulator.
This are two child for RecyclerViews
ChildView.java
public class ChildView {
int image;
String course, price;
public ChildView(int image, String course, String price) {
this.image = image;
this.course = course;
this.price = price;
}
public int getImage() {
return image;
}
public String getCourse() {
return course;
}
public String getPrice() {
return price;
}
}
CourseByType.java
public class CourseByType {
String courseName;
int courseImage;
public CourseByType(String courseName, int courseImage) {
this.courseName = courseName;
this.courseImage = courseImage;
}
public String getCourseName() {
return courseName;
}
public int getCourseImage() {
return courseImage;
}
}
CourseByHeader.java
public class CourseByHeader {
String title;
ArrayList<CourseByType> courseByTypes;
public CourseByHeader(String title, ArrayList<CourseByType> courseByTypes) {
this.title = title;
this.courseByTypes = courseByTypes;
}
public String getTitle() {
return title;
}
public ArrayList<CourseByType> getCourseByTypes() {
return courseByTypes;
}
}
GroupView.java
public class GroupView {
String title;
ArrayList<ChildView> childViewList;
String courseBy;
ArrayList<CourseByType> courseByTypes;
public GroupView(String title, ArrayList<ChildView> childViewList) {
this.title = title;
this.childViewList = childViewList;
}
public String getTitle() {
return title;
}
public ArrayList<ChildView> getChildViewList() {
return childViewList;
}
}
Groupview and CouseByType class have title and child list for recycleradapter
ChildViewAdapter.java
public class ChildViewAdapter extends RecyclerView.Adapter {
ArrayList<ChildView> childViewList;
ArrayList<CourseByType> courseByTypes;
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
public class ViewHolder extends RecyclerView.ViewHolder{
public ViewHolder(View itemView) {
super(itemView);
}
}
public class GroupHolder extends ViewHolder {
public ImageView iamView;
public TextView course, price;
public GroupHolder(View itemView) {
super(itemView);
iamView = (ImageView) itemView.findViewById(R.id.course_image);
course = (TextView) itemView.findViewById(R.id.course_by);
price = (TextView) itemView.findViewById(R.id.price);
}
}
public void addCourse(ArrayList<CourseByType> courseByType){
courseByTypes = courseByType;
}
public void addChild(ArrayList<ChildView> childView){
childViewList = childView;
}
public class Course extends ViewHolder {
public ImageView courseTypeImage;
public TextView courseType;
public Course(View itemView) {
super(itemView);
courseTypeImage = (ImageView)itemView.findViewById(R.id.course_image);
courseType = (TextView)itemView.findViewById(R.id.course_name_course);
}
}
public ChildViewAdapter() {
childViewList = new ArrayList<>();
courseByTypes = new ArrayList<>();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
RecyclerView.ViewHolder vh = null;
View v;
if(viewType == TYPE_HEADER){
v = LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false);
return new GroupHolder(v);
}if(viewType == TYPE_ITEM){
v = LayoutInflater.from(context).inflate(R.layout.type_of_courses, parent, false);
return new Course(v);
}
return vh;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if(holder instanceof GroupHolder){
Log.d("","instance of Group Holder");
ChildView childView = childViewList.get(position);
((GroupHolder)holder).iamView.setImageResource(childView.getImage());
((GroupHolder)holder).course.setText(childView.getCourse());
((GroupHolder)holder).price.setText(childView.getPrice());
return;
}
if(holder instanceof Course){
Log.d("","instance of Course ");
CourseByType courseByType = courseByTypes.get(position);
((Course)holder).courseTypeImage.setImageResource(courseByType.getCourseImage());
((Course)holder).courseType.setText(courseByType.getCourseName());
return;
}
}
#Override
public int getItemCount() {
int size;
if(childViewList.size()>0){
return size = childViewList.size();
}else return size = courseByTypes.size();
}
#Override
public int getItemViewType(int position) {
if(childViewList.size() != 0 && childViewList.size()>0){
return TYPE_HEADER;
}else return TYPE_ITEM;
}
}
This childview adapter has two view types first is one image and 3 text and second view type contain one image and one text.When I pass values from fragment only first view type get displayed and second view type not gets value from fragment.
To show multiple different views in a recyclerview, you have to override getItemViewType() in the recyclerview adapter.
//getItemViewType enables dynamic viewholder creation
#Override
public int getItemViewType(int position) {
//you will need to add a integer with variable name viewTypeCode
//for view1 set viewTypeCode = 100 and for view2 set viewTypeCode = 200
viewTypeCode = itemList.get(position).getViewTypeCode();
return viewTypeCode;
}
This is how the onCreateViewHolder will be different for multiple viewtypes. You will have to modify yours like this
#Override
public FeedViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case 100: return new FeedViewHolder(layoutInflater.inflate(R.layout.v1, parent, false),100);
case 200: return new FeedViewHolder(layoutInflater.inflate(R.layout.v2, parent, false),200);
}
return null;
}
OnBindViewHolder will be similarly modified
#Override
public void onBindViewHolder(final FeedViewHolder holder, int position) {
viewTypeCode = itemList.get(position).getViewTypeCode();
switch ( viewTypeCode) {
case 100:
//your code for v1
case 200:
//your code for v2
}
}
Similarly the ViewHolder class is modified
class FeedViewHolder extends RecyclerView.ViewHolder{
//declare variables here
public FeedViewHolder(View v, int viewType) {
super(v);
switch (viewType) {
//instead of itemView.findViewById you will have to use v.findViewById
case 100:
//your code for v1
case 200:
//your code for v2
}
}
For further reference refer to this SO answer
Don't pass two separate list.Make a custom class like this-
class MyClass {
int viewTypeCode;
CustomClass1 c1;
CustomClass2 c2;
//add the setter getter
}
In your activity while preparing the data.
List<MyClass> itemList = new ArrayList<>();
//put whatever logic you need to make the order of the list
//if CustomClass1 object is put then setViewTypeCode(100), setCustomClass2 = null
//if CustomClass2 object is put then setViewTypeCode(200), setCustomClass1 = null
After data is built, then send this to the adapter.

RecyclerView with one static card and other dynamic cards

I need to do this: a RecycleView with CardView. The first card is static: it show "Details for this order". The other cards after the first are dynamics. So I decided to do this code:
public class DocumentTypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
{
private List<DocumentType> document; //lista di card da riempire
private Context context;
public DocumentTypeAdapter(List<DocumentType>document, Context context)
{
this.document = document;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view;
if(viewType == 0)
{
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_info, parent, false);
ViewSimple simpleView = new ViewSimple(view);
return simpleView;
}
else
{
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_info, parent, false);
DocumentTypeViewHolder documentTypeViewHolder = new DocumentTypeViewHolder(view);
return documentTypeViewHolder;
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
DocumentType documents = document.get(position);
if(getItemViewType(position)!=0)
{
holder.title.setText(documents.getTitle());
holder.cert.setText(documents.getTypeofCertificate());
holder.lastmod.setText(documents.getLastModified());
}
}
#Override
public int getItemCount()
{
return document.size();
}
#Override
public int getItemViewType(int position)
{
return document.size();
}
private class ViewSimple extends RecyclerView.ViewHolder
{
public ViewSimple(View itemView)
{
super(itemView);
}
}
public class DocumentTypeViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
TextView title, lastmod,cert;
public DocumentTypeViewHolder(View itemView)
{
super(itemView);
title = (TextView)itemView.findViewById(R.id.tipo);
lastmod = (TextView)itemView.findViewById(R.id.ultimamodifica);
cert = (TextView)itemView.findViewById(R.id.certificato);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
}
}
}
but it doesn't work.
My question are:
how to make the first card static and other dynamics?
my data are in document list. So how to say to method getItemViewType() that the first card is static and others are generated from the size of the list document?
Edit: this is the code with changes:
public class DocumentTypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
{
private static final int STATIC_CARD = 0;
private static final int DYNAMIC_CARD = 1;
private List<DocumentType> document;
private Context context;
public DocumentTypeAdapter(List<DocumentType>document, Context context)
{
this.document = document;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view;
if(viewType == STATIC_CARD)
{
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_info, parent, false);
ViewSimple simpleView = new ViewSimple(view);
return simpleView;
}
else
{
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.document_card_type, parent, false);
DocumentTypeViewHolder documentTypeViewHolder = new DocumentTypeViewHolder(view);
return documentTypeViewHolder;
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
DocumentType documents = document.get(position);
if(getItemViewType(position)==DYNAMIC_CARD)
{
DocumentTypeViewHolder mHolder = (DocumentTypeViewHolder)holder;
mHolder.data.setText(documents.getData());
mHolder.status.setText(documents.getStatus());
Picasso.with(context).load(documents.getImage().toString()).into(mHolder.image, new com.squareup.picasso.Callback() {
#Override
public void onSuccess() {
Log.d("Picasso","success");
}
#Override
public void onError()
{
Log.d("Picasso","error");
}
});
}
}
#Override
public int getItemCount()
{
return document.size();
}
#Override
public int getItemViewType(int position)
{
if(position == 0)
return STATIC_CARD;
else
return DYNAMIC_CARD;
}
private class ViewSimple extends RecyclerView.ViewHolder
{
public ViewSimple(View itemView)
{
super(itemView);
}
}
public class DocumentTypeViewHolder extends RecyclerView.ViewHolder
{
TextView data, status;
ImageView image;
public DocumentTypeViewHolder(View itemView)
{
super(itemView);
data = (TextView)itemView.findViewById(R.id.dateCharging);
status =(TextView)itemView.findViewById(R.id.statusCharging);
image = (ImageView)itemView.findViewById(R.id.documentImage);
}
}
}
Thanks for your answers
You should override getItemViewType() and make it return a different value when it should be a dynamic card or when its a static card. Since you want the first card to be static you should return a different value when position == 0. This will look something like this:
private static final int STATIC_CARD = 0;
private static final int DYNAMIC_CARD = 1;
#Override
public int getItemViewType(int position) {
if(position == 0) {
return STATIC_CARD;
} else {
return DYNAMIC_CARD;
}
}
Then in your onCreateViewHolder() method you should check the viewType and based on the outcome you should inflate a View, which you were already doing OK, but I would replace the hardcoded 0 with the private static final int STATIC_CARD.
Edit: Just came to my mind, if you only need one static card, you might want to consider placing a CardView in your Fragment/Activity xml layout and place the rest of the dynamic cards in a RecyclerView below that static card.
I'll suggest you to use a library that already correctly implement/handles all that for you: https://github.com/eyeem/RecyclerViewTools
Full disclosure: I wrote the library
Just write your adapter for the dynamic items and then:
DocumentTypeAdapter adapter = new // your adapter here
WrapAdapter wrapAdapter = new WrapAdapter(adapter); // that's from the library
wrapAdapter.addHeader( /* add here your static view */ );
recyclerView.setAdapter(wrapAdapter);
and add those to your build.gradle
repositories {
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
}
dependencies {
compile 'com.eyeem.recyclerviewtools:library:0.0.3-SNAPSHOT#aar'
}

How to Change the viewType of a RecyclerView item onClick

I have created a RecyclerView with Cards as its primary viewtype. What I am trying to achieve is that when user clicks on a item the ViewType of that item is changed from cards to another Viewtype(for example a list textviews placed horizontally scrollable).
My code for RecyclerView Adapter is as follows :
In the below piece of code I have created a arrraylist of enum types to keep track of the clicked state of each row in recyclerview, then I got the size of my dataset and initialized my arraylist for each row with SHOW_PRIMARY_CONTENT
public class DisplayItemsAdapter extends RecyclerView.Adapter<DisplayItemsAdapter.ViewHolder> {
private static ArrayList<clickedState> itemClickedState;
private enum clickedState {
SHOW_PRIMARY_CONTENT,
SHOW_SECONDARY_CONTENT
}
private ArrayList<ItemData> mDataset = new ArrayList<>();
public DisplayItemsAdapter(ArrayList<ItemData> dataset) {
mDataset = dataset;
itemClickedState = new ArrayList<>();
for (int i = 0; i < mDataset.size(); i++) {
itemClickedState.add(i, clickedState.SHOW_PRIMARY_CONTENT);
}
}
Below is my ViewHolder Class which holds references to all my child views, It Implements View.OnClickListener. Why it implements View.OnClickListener is so that it can toggle between clicked states to change viewTypes accordingly.
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView tvItemName;
TextView tvItemNumber;
public ViewHolder(View itemView) {
super(itemView);
tvItemName = (TextView) itemView.findViewById(R.id.tvItemName);
tvItemNumber = (TextView) itemView.findViewById(R.id.tvItemNumber);
tvTicketClass = (TextView) itemView.findViewById(R.id.tvTicketClass);
}
#Override
public void onClick(View v) {
itemClickedState.add(getAdapterPosition(), clickedState.SHOW_SECONDARY_CONTENT);
}
}
This is where I am getting the value of viewType returned by getItemViewType and returning inflated layout
#Override
public DisplayItemsAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View v1 = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.display_Items_row, viewGroup, false);
View v2 = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.display_Items_ticket_class, viewGroup, false);
if (viewType == 0) {
return new ViewHolder(v1);
} else {
return new ViewHolder(v2);
}
}
Then here I m binding the views with values according to the viewType returned by the viewholderusing viewholder.getItemViewType
#Override
public void onBindViewHolder(DisplayItemsAdapter.ViewHolder viewHolder, final int position) {
if (viewHolder.getItemViewType() == 0) {
viewHolder.tvItemName.setText(mDataset.get(position).strItemName);
viewHolder.tvItemNumber.setText(mDataset.get(position).strItemNumber);
} else if (viewHolder.getItemViewType() == 1) {
for (int i = 0; i < mDataset.get(position).strClass.length; i++) {
viewHolder.tvTicketClass.setText(mDataset.get(position).strClass[i]);
}
}
}
#Override
public int getItemCount() {
return mDataset.size();
}
And finally my getItemViewType logic
#Override
public int getItemViewType(int position) {
if (itemClickedState.get(position) == clickedState.SHOW_SECONDARY_CONTENT)
return 1;
return 0;
}
}
What I could not understand is that why is not anything show when I run the code ,,,Everything seems valid to me . Help Me !!!!
see my example:
// RecycleItemObject.java
public class RecycleItemObject {
public static int LAYOUT_ITEM_PORTRAIN = 0;
public static int LAYOUT_ITEM_LANDSCAPE = 1;
private int type;
....................
/**
* #return get layout type of item
*/
public int getType() {
return type;
}
/**
* set layout type of item
* #param type
*/
public void setType(int type) {
this.type = type;
}
}
// adapter
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if (viewType == RecycleItemObject.LAYOUT_ITEM_PORTRAIN) {
view = LayoutInflater.from(context).inflate(R.layout.item_recycle_view_main, parent, false);
} else {
view = LayoutInflater.from(context).inflate(R.layout.item_recycle_view_main_land, parent, false);
}
}
// event click item
#onClick....
curentObject.setType(RecycleItemObject.LAYOUT_ITEM_LANDSCAPE);
// notify item only
notifyItemChanged(itemPosition);
with me it work fine
Hope you have figured out your problem. If not then,I have done it f or you.
The buggy line is
#Override
public void onClick(View v) {
itemClickedState.add(getAdapterPosition(), clickedState.SHOW_SECONDARY_CONTENT);
}
Here what you are doing is adding a new Item to
itemClickedState.add(getAdapterPosition(), clickedState.SHOW_SECONDARY_CONTENT);
This will insert a new item and size of mdataList and itemClickState differs and hence mis matching happens.
Use itemClickedState.set(getAdapterPosition(), clickedState.SHOW_SECONDARY_CONTENT);
instead. And second thing I does not understand what tvTicketClass is . If it is a single TextView, then you should concatenate the string first and them do tvTicketClass.settext(concatenatedstrClass) . Hope you get helped from this post.If have any further issue , please do comment.
override getItemViewType in adapter and return itemtype you want. for more check out this link https://guides.codepath.com/android/Heterogenous-Layouts-inside-RecyclerView

Categories

Resources