How to show exact number of items in RecyclerView?
One solution is to set width
of each child programmatically like.
view.getLayoutParams().width = getScreenWidth() / VIEWS_COUNT_TO_DISPLAY;
And the screen size like this:
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics).widthPixels;
The solution that I have provided below helps in displaying pre-defined number of child items('numOfCardViewItemsOnScreen') in a recyclerView on the screen, also calculates the margins between these items to space them evenly, by taking into account the supplied margin between the items & recyclerView's end margin's (i.e, 'marginAtRecyclerViewsEnds')
Note that I have tested this in devices between 5.0" to 7.0" inch devices & obtained consistent result.
private fun configureCardViewLayoutParams(cardView: CardView, numOfCardViewItemsOnScreen: Int, marginAtRecyclerViewsEnds: Float, marginLeftParam: Float, marginRightParam: Float, marginTopParam: Float, marginBottomParam: Float): ViewGroup.MarginLayoutParams {
val numOfGapsInBetweenItems = numOfCardViewItemsOnScreen - 1
var combinedGapWidth = ((marginLeftParam + marginRightParam) * numOfGapsInBetweenItems) + (marginAtRecyclerViewsEnds * 2)
//Provided approx. adjustment of 2dp to prevent the extreme edges of the card from being cut-off
combinedGapWidth += 2
val combinedGapWidthDp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, combinedGapWidth, cardView.resources.displayMetrics).toInt()
//Since margins/gaps are provided in-between the items, these have to be taken to account & subtracted from the width in-order to obtain even spacing
cardView.layoutParams.width = (getScreenWidth(cardView.context as MainActivity) - combinedGapWidthDp) / numOfCardViewItemsOnScreen
//Margins in-between the items
val marginLeftOfItem = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, marginLeftParam, cardView.resources.displayMetrics).toInt()
val marginRightOfItem = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, marginRightParam, cardView.resources.displayMetrics).toInt()
val marginTopOfItem = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, marginTopParam, cardView.resources.displayMetrics).toInt()
val marginBottomOfItem = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, marginBottomParam, cardView.resources.displayMetrics).toInt()
//Providing the above margins to the CardView
val cardViewMarginParams: ViewGroup.MarginLayoutParams = cardView.layoutParams as ViewGroup.MarginLayoutParams
cardViewMarginParams.setMargins(marginLeftOfItem, marginTopOfItem, marginRightOfItem, marginBottomOfItem)
return cardViewMarginParams
}
The below method helps in calculating the screenWidth as the name implies
private fun getScreenWidth(activity: MainActivity): Int {
var width: Int = 0
val size = Point()
val windowManager = activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager
width = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val bounds = windowManager.currentWindowMetrics.bounds
bounds.width()
} else {
val display: Display? = windowManager.defaultDisplay
display?.getSize(size)
size.x
}
return width
}
Finally inside onCreateViewHolder, utilise the configureCardViewLayoutParams method depicted above & pass in the desired arguments
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyRecyclerViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.row_item_layout, parent, false)
view.layoutParams = configureCardViewLayoutParams(view as CardView, 4, 12f, 4f, 4f, 8f, 8f)
return MyRecyclerViewHolder(view)
}
For the sake of quick understanding, I have also provided the child items xml layout (row_item_layout.xml) So as you can see from the below xml, the root view of our child item layout is a CardView.
<?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:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="5dp"
android:foregroundGravity="center">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView1"
android:layout_width="30dp"
android:layout_height="28dp"
android:layout_marginTop="22dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="7dp"
android:layout_marginTop="18dp"
android:layout_marginEnd="7dp"
android:layout_marginBottom="16dp"
android:ellipsize="end"
android:gravity="center"
android:maxLines="2"
android:text="@{accountOptionsModel.title}"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView1"
tools:text="@tools:sample/full_names" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
There is no special logic within the getCount(), just return the entire list size
override fun getItemCount(): Int = myList.size
Below screenshots are from devices of 5.0", 6.3", 7.02" respectively
In a general way to achieve this there is no straight forward property that recycler view comes with.
The way this is achievable is by sending in the parent width to the adapter..
In a suedo way..
Parent width = parent container width;
InitialiseRecyclerAdapter(parent width) {
on create view holder {
Set the width of ur item layout with a width that divides ur parent width in equal parts;
}
}
I have done the above task as following approach, please refers the following code
On my onCreateViewHolder()
method of my RecycleView Adapter
, i find out the width of the screen and than divided into 3 sections.Please check it once.
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.MY_ITEM_TO_INFALTE, parent, false);
itemView.getLayoutParams().width = (int) (getScreenWidth() / NUMBERS_OF_ITEM_TO_DISPLAY); /// THIS LINE WILL DIVIDE OUR VIEW INTO NUMBERS OF PARTS
return new MyCreationItemAdapter.MyViewHolder(itemView);
}
From above code getScreenWidth()
method which we use on above is as follow,please check it.
public int getScreenWidth() {
WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size.x;
}