Heteregenous RecyclerView Android

Bipin Alee Magar
6 min readMar 28, 2017

Heterogeneity is quite complex while designing the view and at last binding it to different viewHolders. So, to learn this be patience and focused.

Overview:

This is the view that we are going to design.
1.getItemViewType(int position)//returns viewType number that we explictly define.Here we return position according to the object type using instanceof keyword.2.getItemCount()//returns the total number of list size3.onCreateViewHolder(ViewGroup parent, int viewType)//according to viewtype, we return holder of our required type4.onBindViewHolder(RecyclerView.ViewHolder holder, int position)//according to holders' item viewType we set the adapters with respective holder.

This will be my output:

Don’t panic steps 1–5 are just prerequisites….

  1. There is main activity which hosts all the views, so first of all it contains main RecyclerView in xml containing different types of another recyclerViews. Here I am going to use two recyclerview one which scroll vertically and another horizontally. Doesn’t it sounds cool.

activity_main.xml.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.recyclerviewwithinrecyclerview.activities.MainActivity"
>

<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_View"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ccc"
/>
</RelativeLayout>

2. Since activity_main.xml is container of two others recyclerview we need horizontal.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/inner_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

</LinearLayout>

and vertical.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:orientation="vertical"
>

<android.support.v7.widget.RecyclerView
android:id="@+id/inner_recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>

</LinearLayout>

3. Since above horizontal and vertical are also container ,we have to design how a single item of these two views look like.

I’ve used cardview please get the dependency and in drawable add gradient_overlay.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >

<gradient
android:angle="90"
android:centerColor="@android:color/transparent"
android:endColor="#C4000000"
android:startColor="#C4000000"
android:type="linear"
/>

<corners
android:radius="0dp"
/>

</shape>

horizontal_single_row.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:layout_width="250dp"
android:layout_height="270dp"
android:layout_margin="5dp"
android:background="#FFFFFF"
android:elevation="5dp"
android:orientation="vertical"
android:padding="5dp"
>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>

<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>

<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="150dp"
android:scaleType="center"
/>

<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="8dp"
android:textColor="#fff"
android:text="Title"
android:textSize="28sp"
/>

<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@drawable/gradient_overlay"
android:id="@+id/view"
/>

</FrameLayout>

<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="this is the description"
/>

<TextView
android:id="@+id/published_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="2073/2/2"
/>
</LinearLayout>

</android.support.v7.widget.CardView>

4. Now to justify above single row we make some POJO.

SingleHorizontal.java (for horizontal view)

 
public class SingleHorizontal {

private int images;
private String title;
private String desc;
public SingleHorizontal() {

}

public SingleHorizontal(int images, String title, String desc, String pubDate) {
this.images = images;
this.title = title;
this.desc = desc;
this.pubDate = pubDate;
}

public String getPubDate() {
return pubDate;
}

public void setPubDate(String pubDate) {
this.pubDate = pubDate;
}

public String getDesc() {
return desc;
}

public void setDesc(String desc) {
this.desc = desc;
}

private String pubDate;

public int getImages() {
return images;
}

public void setImages(int images) {
this.images = images;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}
}

SingleVertical.java (for vertical view)

 
public class SingleVertical {

private String header, subHeader;
private int image;

public SingleVertical( ) {

}

public SingleVertical(String header, String subHeader, int image) {
this.header = header;
this.subHeader = subHeader;
this.image = image;
}

public String getHeader() {
return header;
}

public void setHeader(String header) {
this.header = header;
}

public String getSubHeader() {
return subHeader;
}

public void setSubHeader(String subHeader) {
this.subHeader = subHeader;
}

public int getImage() {
return image;
}

public void setImage(int image) {
this.image = image;
}
}

5. Now to bind these views horizontal and vertical (for now) we define adapters for each class.

HorizontalAdapter.java(to bind horizontal view with data)

I am defining the viewholder class within adapter so notice that.

 
public class HorizontalAdapter extends RecyclerView.Adapter<HorizontalAdapter.MyViewHolder> {

ArrayList<SingleHorizontal> data = new ArrayList<>();

public HorizontalAdapter(ArrayList<SingleHorizontal> data) {
this.data = data;

}

@Override
public
HorizontalAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.horizontal_single_row, parent, false);
return new MyViewHolder(view);
}

@Override
public void
onBindViewHolder(HorizontalAdapter.MyViewHolder holder, int position) {

holder.description.setText(data.get(position).getDesc());
holder.title.setText(data.get(position).getTitle());
holder.pubDate.setText(data.get(position).getPubDate());
holder.image.setImageResource(data.get(position).getImages());
}

@Override
public int
getItemCount() {
return data.size();
}

public class MyViewHolder extends RecyclerView.ViewHolder {
TextView title, description, pubDate;
ImageView image;

public MyViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
description = (TextView) itemView.findViewById(R.id.description);
pubDate = (TextView) itemView.findViewById(R.id.published_date);
image = (ImageView) itemView.findViewById(R.id.image_view);
}
}
}

VerticalAdapter.java(to bind vertical view with data)


public class VerticalAdapter extends RecyclerView.Adapter<VerticalAdapter.MyViewHolder> {
private ArrayList<SingleVertical> data = new ArrayList<>();

public VerticalAdapter(ArrayList<SingleVertical> data) {
this.data = data;
}

@Override
public
VerticalAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.vertical_single_row, parent, false);
return new MyViewHolder(view);
}

@Override
public void
onBindViewHolder(VerticalAdapter.MyViewHolder holder, int position) {
holder.image.setImageResource(data.get(position).getImage());
holder.title.setText(data.get(position).getHeader());
holder.description.setText(data.get(position).getSubHeader());
}

@Override
public int
getItemCount() {
return data.size();
}

public class MyViewHolder extends RecyclerView.ViewHolder {
ImageView image;
TextView title, description;

public MyViewHolder(View itemView) {
super(itemView);
image = (ImageView) itemView.findViewById(R.id.image);
title = (TextView) itemView.findViewById(R.id.title);
description = (TextView) itemView.findViewById(R.id.description);
}
}
}

6. NOW THE MAGIC BEGINS …HERE IS THE MAIN LOGIC TO BIND BOTH THE RECYCLERVIEWS IN ONE RECYCLERVIEW.

We construct MainAdapter.java.

Since we are dealing with different viewtypes we override extra function getItemViewTypes().

Here is the code :

public class MainAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private Context context;
private ArrayList<Object> items;
private final int VERTICAL = 1;
private final int HORIZONTAL = 2;

public MainAdapter(Context context, ArrayList<Object> items) {
this.context = context;
this.items = items;
}
//this method returns the number according to the Vertical/Horizontal object
@Override
public int
getItemViewType(int position) {
if (items.get(position) instanceof SingleVertical)
return VERTICAL;
if (items.get(position) instanceof SingleHorizontal)
return HORIZONTAL;
return -1;
}
//this method returns the holder that we've inflated according to the viewtype.
@Override
public
RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view;
RecyclerView.ViewHolder holder;
switch (viewType) {
case VERTICAL:
view = inflater.inflate(R.layout.vertical, parent, false);
holder = new VerticalViewHolder(view);
break;
case HORIZONTAL:
view = inflater.inflate(R.layout.horizontal, parent, false);
holder = new HorizontalViewHolder(view);
break;

default:
view = inflater.inflate(R.layout.horizontal, parent, false);
holder = new HorizontalViewHolder(view);
break;
}


return holder;
}
//here we bind view with data according to the position that we have defined.
@Override
public void
onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == VERTICAL)
verticalView((VerticalViewHolder) holder);
else if (holder.getItemViewType() == HORIZONTAL)
horizontalView((HorizontalViewHolder) holder);
}

private void verticalView(VerticalViewHolder holder) {

VerticalAdapter adapter1 = new VerticalAdapter(getVerticalData());
holder.recyclerView.setLayoutManager(new LinearLayoutManager(context));
holder.recyclerView.setAdapter(adapter1);
}


private void horizontalView(HorizontalViewHolder holder) {
HorizontalAdapter adapter = new HorizontalAdapter(getHorizontalData());
holder.recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
holder.recyclerView.setAdapter(adapter);
}


@Override
public int
getItemCount() {
return items.size();
}

public class HorizontalViewHolder extends RecyclerView.ViewHolder {

RecyclerView recyclerView;

HorizontalViewHolder(View itemView) {
super(itemView);
recyclerView = (RecyclerView) itemView.findViewById(R.id.inner_recyclerView);
}
}

public class VerticalViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;

VerticalViewHolder(View itemView) {
super(itemView);
recyclerView = (RecyclerView) itemView.findViewById(R.id.inner_recyclerView);
}
}

}

7.At last in MainActivity.java we provide some data (I am providing some static data) and set the MainAdapter.java.


public class MainActivity extends AppCompatActivity {
private ArrayList<Object> objects = new ArrayList<>();

@Override
protected void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_View);
MainAdapter adapter = new MainAdapter(this, getObject());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));

}

private ArrayList<Object> getObject() {
objects.add(getVerticalData().get(0));
objects.add(getHorizontalData().get(0));
return objects;
}

public static ArrayList<SingleVertical> getVerticalData() {
ArrayList<SingleVertical> singleVerticals = new ArrayList<>();
singleVerticals.add(new SingleVertical("Charlie Chaplin", "Sir Charles Spencer \"Charlie\" Chaplin, KBE was an English comic actor,....", R.mipmap.charlie));
singleVerticals.add(new SingleVertical("Mr.Bean", "Mr. Bean is a British sitcom created by Rowan Atkinson and Richard Curtis, and starring Atkinson as the title character.", R.mipmap.mrbean));
singleVerticals.add(new SingleVertical("Jim Carrey", "James Eugene \"Jim\" Carrey is a Canadian-American actor, comedian, impressionist, screenwriter...", R.mipmap.jim));
return singleVerticals;
}


public static ArrayList<SingleHorizontal> getHorizontalData() {
ArrayList<SingleHorizontal> singleHorizontals = new ArrayList<>();
singleHorizontals.add(new SingleHorizontal(R.mipmap.charlie, "Charlie Chaplin", "Sir Charles Spencer \"Charlie\" Chaplin, KBE was an English comic actor,....", "2010/2/1"));
singleHorizontals.add(new SingleHorizontal(R.mipmap.mrbean, "Mr.Bean", "Mr. Bean is a British sitcom created by Rowan Atkinson and Richard Curtis, and starring Atkinson as the title character.", "2010/2/1"));
singleHorizontals.add(new SingleHorizontal(R.mipmap.jim, "Jim Carrey", "James Eugene \"Jim\" Carrey is a Canadian-American actor, comedian, impressionist, screenwriter...", "2010/2/1"));
return singleHorizontals;
}


}

Thats all …hope you enjoyed it.

If you have any queries please let me know it.

Find this on GitHub.

--

--