How to set different columns for rows in android gridview - android

I want to have a gridview similar to this
Every odd numbered row will have two images of big size and even numbered rows will have four smaller images.How can I achieve this?

I have something similar and i solved with the new RecyclerView.
I created a Fragment with an a RecyclerView.
RecyclerView on xml:
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/filter_subtypes" android:layout_width="match_parent" android:layout_height="match_parent" />
On your Fragment/Activity (OnViewCreated in my fragment case).
I find the RecyclerView and set an Adapter- a normal Adapter class inherit from RecyclerView.Adapter< YOUR VIEW HOLDER class >-
And then i create a GridLayoutManager
final GridLayoutManager mng_layout = new GridLayoutManager(this.getActivity(), TOTAL_CELLS_PER_ROW/*In your case 4*/);
Then i override this method to set a dynamic numbers of columns (cells)
mng_layout.setSpanSizeLookup( new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
switch( adapterSubtype.getItemViewType(position) ) {
case FilterSubtypesAdapter.TYPE_LOW:
return TOTAL_CELLS_PER_ROW;
case FilterSubtypesAdapter.TYPE_HIGH:
return 2;
default:
return -1;
}
}
});
myRecyclerView.setLayoutManager(mng_layout);
With this you will get dynamic numbers of cell on your rows.
EXTRA:
Then if you are using the same view/type view on your adapter, you will get the same w & h view. You will need to create 2 xml views for TYPE_HIGH and other view for TYPE_LOW.
So, in your adapter, you need to have 2 kind of data (1 for high images and 1 for low images).
You must override this methods
#Override
public SubtypeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = null;
if (viewType==TYPE_HIGH) {
view = inflater.inflate(R.layout.item_image_high, parent, false);
} else {
view = inflater.inflate(R.layout.item_image_low, parent, false);
}
return new SubtypeViewHolder(view, viewType);
}
#Override
public int getItemViewType(int position) {
return (list.get(position).getType()==Subtype_type.HIGH) ? TYPE_HIGH : TYPE_LOW;
}
I hope i was clear, any problem tell me.

Instead of considering a single image views i am taking group of three images as a single grid item,
try this inside your grid adapter
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linear"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/green"
android:orientation="vertical">
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="#drawable/user"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/image_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:scaleType="fitXY"
android:src="#drawable/user"
/>
<ImageView
android:id="#+id/image_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/user"
android:scaleType="fitXY"
android:layout_weight="1"
/>
</LinearLayout>
</LinearLayout>
and your grid view would be like
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/RelativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:numColumns="2"
>
</GridView>
The only thing you have to take care of is, the sequence of your image. might be this will help you

If you are using RecyclerView for GridView, then there is solution that should work for you:
GridLayoutManager layoutManager = new GridLayoutManager(this, 4);
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
int mod = position % 6;
if(position == 0 || position == 1)
return 2;
else if(position < 6)
return 1;
else if(mod == 0 || mod == 1)
return 2;
else
return 1;
}
});
recyclerView.setLayoutManager(layoutManager);
Hope this work for you!

I guess the best way to do is using recycler view..
Also it is preferred over list/grid for performance
May be below links can help a lot - All are related to Two way View by Lucas
https://github.com/lucasr/twoway-view
https://plus.google.com/+LucasRocha/posts/WBaryNqAHiy
http://lucasr.org/2014/07/31/the-new-twowayview/

There is how does it work in my project I have different height of cells and also header
adapter:
public class AdapterRecViewMain
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<BaseMarkerElement> mainCardList;
private final int HEADER_VIEW = 0;
private final int FOOTER_VIEW = 1;
public AdapterRecViewMain() {
}
public void setData(List<BaseMarkerElement> mainCardList) {
this.mainCardList = mainCardList;
}
#Override public int getItemViewType(int position) {
if (position == 0) {
return HEADER_VIEW;
}
return FOOTER_VIEW;
}
#Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
if (type == FOOTER_VIEW) {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.card_main_activity, viewGroup, false);
return new MainCardViewHolder(v);
} else {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.header_view_main_activity, viewGroup, false);
return new HeaderViewHolder(v);
}
}
#Override public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int positionItem) {
final int position = viewHolder.getAdapterPosition();
if (viewHolder instanceof HeaderViewHolder) {
StaggeredGridLayoutManager.LayoutParams layoutParams =
(StaggeredGridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams();
layoutParams.setFullSpan(true);
BaseMarkerElement item = mainCardList.get(position);
if (item instanceof HeaderView) {
HeaderView header = (HeaderView) mainCardList.get(position);
// need to add implementation
}
} else if (viewHolder instanceof MainCardViewHolder) {
MainCardViewHolder currentView = (MainCardViewHolder) viewHolder;
CardMainActivity currentCard = (CardMainActivity) mainCardList.get(position);
currentView.ivMainCard.setImageResource(currentCard.getIvMainCard());
currentView.tvBrandName.setText(currentCard.getTvBrandName());
currentView.tvPrice.setText(currentCard.getTvPrice());
currentView.tvType.setText(currentCard.getTvType());
}
}
#Override public int getItemCount() {
return mainCardList.size();
}
private class MainCardViewHolder extends RecyclerView.ViewHolder {
ImageView ivMainCard;
TextView tvBrandName;
TextView tvType;
TextView tvPrice;
MainCardViewHolder(View view) {
super(view);
ivMainCard = (ImageView) view.findViewById(R.id.imageViewMainCard);
tvBrandName = (TextView) view.findViewById(R.id.tvBrandName);
tvType = (TextView) view.findViewById(R.id.tvType);
tvPrice = (TextView) view.findViewById(R.id.tvPrice);
}
}
private class HeaderViewHolder extends RecyclerView.ViewHolder {
public HeaderViewHolder(View itemView) {
super(itemView);
}
}
}
In your activity :
private AdapterRecViewMain adapter;
private RecyclerView rvMain;
#Override protected void onResume() {
super.onResume();
Logger.logGeneral("onResume()");
if (adapter == null) {
setUpRecView();
}
}
private void setUpRecView() {
adapter = new AdapterRecViewMain();
adapter.setData(controller.loadData());
rvMain = (RecyclerView) findViewById(R.id.rvMain);
final StaggeredGridLayoutManager layoutManager =
new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
rvMain.setLayoutManager(layoutManager);
rvMain.addOnScrollListener(scrollListener);
rvMain.setAdapter(adapter);
adapter.notifyDataSetChanged();
rvMain.invalidate();
}

You should set in RecyclerView :
recyclerView.setLayoutManager(new GridLayoutManager(this, 4));

Create two different XML files and inflate based on position in your Adapter like below.
if(position%2==0){
//Inflate Even number layout with 4 images
}else{
//Inflate ODD number layout with 2 images
}

Did you try a RecyclerView in a combination with a StaggeredGridLayoutManager?
This combination results in something like this: video.
I think, this is what you are looking for.

Try this ,
https://github.com/etsy/AndroidStaggeredGrid
Staggered-Grid View ,
Extremely simple , easy to use.

Use Expandable list view and provide different view for each row.
http://developer.android.com/reference/android/widget/ExpandableListView.html

Related

How to custom place an item in StaggeredGridLayout?

I have a RecyclerView that holds user hobbies in profile fragment. I placed items in RecyclerView with StaggeredGridLayout. Like this:
But I want to show my items a little bit of custom view. The custom view I want:
And this is my item XML file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center_horizontal"
android:orientation="vertical"
android:layout_width="match_parent" android:layout_height="wrap_content">
<TextView
android:id="#+id/hobby_profile_title"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#drawable/hobby_background_3"
android:text="Spor"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:textSize="11sp"
android:layout_marginBottom="10dp"
android:gravity="center"
android:textColor="#fff"
android:fontFamily="#font/inter_semibold"/>
</LinearLayout>
HobbyAdapter:
public class ProfileHobbyAdapter extends RecyclerView.Adapter<ProfileHobbyViewPager> {
private ArrayList<ProfileHobby> hobby_title;
public ProfileHobbyAdapter(ArrayList<ProfileHobby> hobby_title) {
this.hobby_title = hobby_title;
}
#NonNull
#Override
public ProfileHobbyViewPager onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.profil_hobby_card, parent, false);
ProfileHobbyViewPager profileHobbyViewPager = new ProfileHobbyViewPager(view);
return profileHobbyViewPager;
}
#Override
public void onBindViewHolder(#NonNull ProfileHobbyViewPager holder, int position) {
holder.hobby_profile_title.setText(hobby_title.get(position).getHobby_title());
}
#Override
public int getItemCount() {
return hobby_title.size();
}
}
Can I get this view using StaggeredGrid? Or should I look for another alternative? Thank you for helpings.
you'd better use GridLayoutManager instead of StaggeredGridLayout
I think following code will solve your problem:
in kotlin:
val layoutManager= GridLayoutManager(activity, 3)
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return when (position % 2) {
0 -> 2 //in even rows you have two columns
else -> 3 //in odd rows you have three columns
}
}
}
recyclerView.layoutManager = layoutManager
in java:
GridLayoutManager layoutManager = new GridLayoutManager(this, 3);
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
switch (position % 2) {
case 0: return 2; //in even rows you have two columns
case 1: return 3; //in odd rows you have two columns
}
}
});
recyclerview.setlayoutmanager(layoutManager)
in this code, first grid layout has been created with 3 columns, then even rows (even position which specified by position % 2) will return 2 spans and odd rows will show 3 spans.

How can I make the Android RecyclerView responsive to fit the screen initially?

Sometimes RecyclerView shows empty spaces at bottom if the screen is large or it has fewer items to cover the screen. Also sometimes it shows some items partially if it has more items. What I want is:
RecyclerView will cover the full available space with the given number
of rows. It will always fill the screen, no matter what is the size of
the screen.
How can I do that?
use match_parent for both width and height.
I'm posting my solution now for any future questioner. Here, by the word RESPONSIVE, I want the Items to take the available screen-space equally. For example, if we want 4 rows initially, the 4 rows will cover up the screen fully; that means, no item will be visible partially when the RecyclerView appears on the screen for the first time. And this will only work if the RecyclerView has fixed height irrespective of its Children, means, don't give WRAP_CONTENT to RecyclerView layout_height, give anything else like MATCH_PARENT or Constrained height.
Step1: You need to pass a parameter rows to the Adapter. You also need to pass the RecyclerView to the Adapter.
Step2: We need to keep a FLAG which will decide when to reveal the Child Items on the Screen. This FLAG will be FALSE initially, this will be TRUE when we finish calculating the available HEIGHT of RecyclerView on the screen. When we get the height of RecyclerView, we divide it by rows and get the height of each row. So we need to put a OnGlobalLayoutListener on the RecyclerView.
Here is a sample code.
RecyclerView layout will be like:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="0dp"
android:layout_height="0dp"
android:id="#+id/recycler_view"
tools:listitem="#layout/item"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Item layout will be like:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="true"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="5dp">
<TextView
android:padding="15dp"
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:enabled="true"
android:focusable="true"
android:longClickable="true"
android:textIsSelectable="true" />
</androidx.cardview.widget.CardView>
Adapter will be like:
public class ResponsiveItemListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements View.OnClickListener
{
public static final int NUMBER_OF_ROWS_AUTO = -1;
Context context;
LayoutInflater layoutInflater;
RecyclerViewItemClickListeners listener;
List<Item> items;
RecyclerView recyclerView;
int numberOfRows;
int rowHeightInPx = 0;
boolean itemHeightCalculationCompleted = false;
public ResponsiveItemListAdapter(Context context, List<Item> items, RecyclerViewItemClickListeners listener, RecyclerView rv, int rows)
{
super();
this.context = context;
this.items = items;
this.listener = listener;
this.layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.recyclerView = rv;
this.numberOfRows = rows;
if (this.numberOfRows > 0)
{
this.recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
if (recyclerView.getMeasuredHeight() > 0)
{
recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
setRowHeightInPx(recyclerView.getMeasuredHeight() / numberOfRows);
itemHeightCalculationCompleted = true;
notifyDataSetChanged();
}
}
});
} else
{
itemHeightCalculationCompleted = true;
}
}
public int getRowHeightInPx()
{
return rowHeightInPx;
}
public void setRowHeightInPx(int rowHeightInPx)
{
this.rowHeightInPx = rowHeightInPx;
}
#Override
public int getItemCount()
{
if (this.items != null && this.itemHeightCalculationCompleted)
return this.items.size();
else
return 0;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
RecyclerView.ViewHolder vh;
View view = this.layoutInflater.inflate(R.layout.item, parent, false);
if (getRowHeightInPx() > 0)
{
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
layoutParams.height = getRowHeightInPx();
layoutParams.width = MATCH_PARENT;
view.setLayoutParams(layoutParams);
}
vh = new GeneralViewHolder(view);
return vh;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
Item page = items.get(position);
CardView view = ((CardView) ((GeneralViewHolder) holder).getView());
((GeneralViewHolder) holder).getTitle().setText(page.getTitle());
((GeneralViewHolder) holder).getView().setOnClickListener(this);
((GeneralViewHolder) holder).getView().setTag(position);
}
#Override
public void onViewRecycled(RecyclerView.ViewHolder holder)
{
super.onViewRecycled(holder);
}
#Override
public void onClick(View v)
{
int position = (int) v.getTag();
this.listener.onRecyclerViewItemClick(this.items, position);
}
public class GeneralViewHolder extends RecyclerView.ViewHolder
{
View view;
TextView title;
public GeneralViewHolder(View itemView)
{
super(itemView);
view = itemView;
title = itemView.findViewById(R.id.title);
}
public View getView()
{
return view;
}
public TextView getTitle()
{
return title;
}
}
public interface RecyclerViewItemClickListeners
{
void onRecyclerViewItemClick(List<Item> items, int position);
}
}
Set the adapter like this:
public class MainActivity extends AppCompatActivity implements ResponsiveItemListAdapter.RecyclerViewItemClickListeners
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<Item> items = new ArrayList<>();
items.add(new Item("One"));
items.add(new Item("Two"));
items.add(new Item("Three"));
items.add(new Item("Four"));
items.add(new Item("Five"));
items.add(new Item("Six"));
items.add(new Item("Seven"));
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(new ResponsiveItemListAdapter(this, items, this, recyclerView, 3));
}
#Override
public void onRecyclerViewItemClick(List<Item> items, int position)
{
Toast.makeText(this, items.get(position).getTitle(), Toast.LENGTH_LONG).show();
}
}
And here is the output:

Image collage in recycler adapter

I have a typical recycler adapter set up. Some of the items in the adapter have images, sometimes just one image, sometimes 20. I want to create an image collage, like the one below, depending on the number of images in each item:
I have 10 different layouts. The first is to be used when the item only has 1 image (1 ImageView in the layout), another used when the item has 2 images (2 ImageViews in the layout), another used when the item has 3 images, etc. If the item has over 10 images, it uses the layout with 10 ImageViews and hides the rest of the images. The layouts are named:
one_image.xml
two_images.xml
three_images.xml
... etc ...
Here is my Recycler adapter:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private static Context context;
private List<Message> mDataset;
public RecyclerAdapter(Context context, List<Message> myDataset) {
this.context = context;
this.mDataset = myDataset;
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, View.OnClickListener {
public TextView title;
public ViewHolder(View view) {
super(view);
view.setOnCreateContextMenuListener(this);
title = (TextView) view.findViewById(R.id.title);
}
}
#Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_layout, parent, false);
ViewHolder vh = new ViewHolder((LinearLayout) view);
return vh;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Message item = mDataset.get(position);
holder.title.setText(item.getTitle());
int numImages = item.getImages().size();
if (numImages > 0) {
// Show image collage
}
}
#Override
public int getItemCount() {
return mDataset.size();
}
}
Here is the main layout, message_layout.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="match_parent">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
// Image collage layout
</LinearLayout>
And this is one of the image collage layouts, two_images.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:orientation="vertical">
<ImageView
android:id="#+id/image_one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
/>
<ImageView
android:id="#+id/image_two"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
/>
</LinearLayout>
So the question is, how do I load/inflate the correct layout depending on the number of images into the recycler adapter, and populate the layout with the images?
You can use StaggeredGridLayoutManager to achieve above type of layouts. Click here for more information about StaggeredGridLayoutManager
There are a number of libraries for staggered gridview. you can use any of them. I recommend to use this:
AndroidStaggeredGrid
You should create a custom ViewHolder for each one of your layouts.
Imagine you have this ViewHolder: TwoImagesViewHolder
public class TwoImagesViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public ImageView imageOne;
public ImageView imageTwo;
public TwoImagesViewHolder(#NonNull View view) {
super(view);
title = (TextView)view.findViewById(R.id.title);
imageOne = (ImageView)view.findViewById(R.id.image_one);
imageTwo = (ImageView)view.findViewById(R.id.image_two);
}
}
Inside the adapter you can use your holder like this:
#Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Message item = mDataset.get(position);
int numImages = item.getImages().size();
if (numImages == 2) {
return new TwoImagesViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.message_layout, parent, false))
}
// Add all the conditions for your custom ViewHolders
return DefaultViewHolder; // Define a Default holder
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Message item = mDataset.get(position);
int numImages = item.getImages().size();
if (numImages == 2) {
// Show image collage
TwoImagesViewHolder holder = (TwoImagesViewHolder)viewHolder;
holder.title.setText(item.getTitle());
holder.image_one.setImageResource(...);
holder.image_two.setImageResource(...);
}
// Add all the conditions for your custom ViewHolders
}
You need to create all your conditions to instance the correct layout holder and remember to have the same conditions for the onCreateViewHolder and onBindViewHolder.

ScrollView and GridView clashes

I have used a scrollview because my view is long and I need to enable the user to scroll down to view the items such as TextViews and ImageViews. However at the bottom I need to have a GridView to display an infinite list of images.
I need to be able to scroll to view the textviews
And
I also need to be able to reach the GridView and scroll away
However, I realised that you can't have a GridView inside a Scrollview since they both involve scrolling and some weird bugs keeps me from scrolling the GridView. What is the alternative to my situation?
Code sample:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="30dp"
android:text="Hello there"
android:textColor="#CC000000"
android:textSize="25sp" />
<TextView
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="30dp"
android:text="Partner Name: "
android:textColor="#CC000000"
android:textSize="25sp" />
<!-- Lot more TextViews -->
<!-- And then comes the GridView -->
<GridView
android:id="#+id/picturefeed"
android:numColumns="3"
android:layout_marginTop="20dp"
android:layout_below="#+id/partner_details"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</GridView>
</ScrollView>
You need a heterogenous RecyclerView with a GridLayoutManager.
You should check out the Creating Lists and Cards guide.
Here is a sample:
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_main_layout);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.your_recycler_view);
final MyAdapter adapter = new MyAdapter();
GridLayoutManager layoutManager = new GridLayoutManager(this, 3); // a row can be 3 spans wide
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
switch(adapter.getItemViewType(position)){
case MyAdapter.TYPE_TEXT:
return 3; // it's going to take up a row
case MyAdapter.TYPE_IMAGE:
return 1; // it's going to take up 1/3 of a row
default:
return -1;
}
}
});
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final int TYPE_TEXT = 1;
public static final int TYPE_IMAGE = 2;
#Override
public int getItemViewType (int position) {
if (position < 2) { // the first two items of the RecyclerView will be the TextView ones
// you can (should?) use a more sophisticated method if you want to
return TYPE_TEXT;
}
// the rest of the items are images
return TYPE_IMAGE;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case TYPE_TEXT:
View v1 = inflater.inflate(R.layout.layout_vh_text, parent, false);
viewHolder = new TextViewHolder(v1);
break;
case TYPE_IMAGE:
View v2 = inflater.inflate(R.layout.layout_vh_image, parent, false);
viewHolder = new ImageViewHolder(v2);
break;
default:
throw new IllegalArgumentException("Unsupported view type: " + viewType);
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()) {
case TYPE_TEXT:
TextViewHolder vh1 = (TextViewHolder) viewHolder;
// do something with vh1
break;
case TYPE_IMAGE:
ImageViewHolder vh2 = (ImageViewHolder) viewHolder;
// do something with vh2
break;
default:
throw new IllegalArgumentException("Unsupported view type: " + viewType);
}
}
public class TextViewHolder extends RecyclerView.ViewHolder {
// ...
}
public class ImageViewHolder extends RecyclerView.ViewHolder {
// ...
}
// rest of the adapter's code, not explained here as it's not part of the question
}

how to have variable row height in recyclerview

I am trying to create a recyclerview in a nav drawer with the header showing the profile information. I would like to have a header height more than the other row elements. below is my header layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#color/green"
android:orientation="vertical"
android:weightSum="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:textColor="#ffffff"
android:text="XXXXX"
android:textSize="32sp"
android:textStyle="bold"
/>
</LinearLayout>
</RelativeLayout>
When I set this to the header of the recycler view , the 200dp height is not reflecting in the UI
RecyclerView.Adapter<NavDrawerListViewHolder> adapter = new NavDrawerListAdapter(this,TITLES,this);
navList.setAdapter(adapter);
Below is the adapter for the recyclerview :
public class NavDrawerListAdapter extends RecyclerView.Adapter<NavDrawerListViewHolder> {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
Context mContext;
String[] mCharacterList;
IListItemClickListener mListener;
int holderViewType=0;
public NavDrawerListAdapter(Context context, String[] characters, IListItemClickListener clickListener) {
mContext = context;
mCharacterList = characters;
mListener = clickListener;
}
#Override
public NavDrawerListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
NavDrawerListViewHolder viewHolder;
holderViewType = viewType;
if(viewType == TYPE_HEADER) {
View v = LayoutInflater.from(mContext).inflate(R.layout.header,null);
viewHolder = new NavDrawerListViewHolder(v,TYPE_HEADER,mListener);
} else {
View v = LayoutInflater.from(mContext).inflate(R.layout.nav_item_row,null);
viewHolder = new NavDrawerListViewHolder(v,TYPE_ITEM,mListener);
}
return viewHolder;
}
#Override
public void onBindViewHolder(NavDrawerListViewHolder holder, int position) {
if(holderViewType == TYPE_HEADER) {
Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "Roboto-Thin.ttf");
holder.name.setTypeface(typeface);
} else {
holder.characterName.setText(mCharacterList[position - 1]);
}
}
#Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_HEADER;
}
return TYPE_ITEM;
}
#Override
public int getItemCount() {
return mCharacterList.length + 1;
}
Replace:
LayoutInflater.from(mContext).inflate(R.layout.header,null);
with:
LayoutInflater.from(mContext).inflate(R.layout.header, parent, false);
and the same for all your other inflate() calls. If you know the parent container for the layout being inflated, always supply it to the inflate() call. In particular, RelativeLayout needs this, if it is the root view of the layout being inflated.
Also, consider using getLayoutInflater() on the Activity instead of LayoutInflater.from(). It may be that if you pass the Activity into from() that you will get equivalent results. However, in general, you always want to use a LayoutInflater that knows about the Activity and its theme, so you get the right results.

Categories

Resources