Reputation: 331
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?
Upvotes: 0
Views: 3084
Reputation: 340
In my situation, I discovered the following method for filling the complete width, regardless of how many items there are—two or six? Examine it to see whether it fits your use case. card_live_bottom_menu
would be your recyclerview's item
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvBottomMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/navigation_bar_color"
android:clipToPadding="false"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:listitem="@layout/card_live_bottom_menu"
tools:itemCount="6"
app:spanCount="6"
/>
As shown below, programmatically set the item count to the recyclerview. list
would be your items list
val layoutManager =
GridLayoutManager(this, list.size, GridLayoutManager.VERTICAL, false)
binding.recyclerView.layoutManager = layoutManager
binding.recyclerView.adapter = adapter
Here is the output
Upvotes: 0
Reputation: 331
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:
Upvotes: 0