I want to use RecyclerView with GridLayoutManager to achieve something like that:
Here is GridLayoutManager with horizontal orientation and 2 rows. What's important for me here is that RecyclerView is set as wrap_content.
So I tried to achieve my goal with such code:
MainActivity.kt
class MainActivity : AppCompatActivity() {
private val adapter = Adapter()
private val layoutManager = GridLayoutManager(this, 2, RecyclerView.HORIZONTAL, false)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView.adapter = adapter
recyclerView.layoutManager = layoutManager
adapter.submitList(listOf(Unit, Unit, Unit, Unit))
}
}
Adapter.kt
class Adapter : ListAdapter<Any, ItemHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemHolder {
val itemView = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
return ItemHolder(itemView)
}
override fun onBindViewHolder(holder: ItemHolder, position: Int) {
}
override fun getItemViewType(position: Int): Int {
return when {
position % 2 == 0 -> R.layout.item_small
else -> R.layout.item_normal
}
}
class DiffCallback : DiffUtil.ItemCallback<Any>() {
override fun areItemsTheSame(oldItem: Any, newItem: Any) = false
override fun areContentsTheSame(oldItem: Any, newItem: Any) = false
}
class ItemHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
}
activity_main.xml
<?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:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
item_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="8dp"
android:background="#color/colorAccent" />
item_small.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_margin="8dp"
android:background="#color/colorAccent" />
Unfortunately as the result, each row stretches to the largest row in grid:
The question is how can I remove the spacing between first row and second row? Keep in mind that I have to have scrollable horizontal grid that its height depends on its content. And items have to have fixed size.
Assuming you know the ratios between heights of individual rows, you can try to use SpanSizeLookup to adjust height of each row. In your simple case, the smaller item (50dp) will take one row (span size 1) while the larger item (100dp) will take two rows (span size 2) so the whole grid overall will contain 3 rows.
Of course, for a more complex row configuration, the ratios might get a little more complicated: Say I wanted rows of heights 32dp/48dp/64dp, then the height ratios are 32/144, 48/144 and 64/144, which we can simplify to 2/9, 3/9, 4/9, getting 9 rows in total, with span sizes 2, 3, and 4 for individual items. In extreme cases, this can result in large number of rows (when the fractions cannot be simplified), but assuming you are using some type of grid (x8, x10, etc.) and the items are reasonably sized, it should still be manageable.
Anyway, in your case, the code would be this:
val layoutManager = GridLayoutManager(this, 3, RecyclerView.HORIZONTAL, false)
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int) = when (position % 2) {
0 -> 1 // 50dp item
else -> 2 // 100dp item
}
}
Given more rows, the when statement is going to get more complex, but if you already have the adapter at hand, you can use getItemViewType to differentiate individual rows in the when statement more easily.
If the number of item types is large or changes often (for example different item types on different screens), you can of course also implement the logic above in code, assuming you have access to the heights of the individual item types. Simply sum the heights to obtain the denominator and then find greatest common divisor of all heights and the sum to find the "simplification factor".
I think GridLayoutManager by default constraints the child views to be exactly same sizes.
I adjust the code to use a LinearLayoutManager, and the view for ViewHolder is to wrap two types views into a RelativeLayout.
See some code below:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:id="#+id/top"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_margin="8dp"
android:layout_alignParentTop="true"
android:background="#color/colorAccent" />
<View
android:id="#+id/bottom"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="8dp"
android:layout_below="#+id/top"
android:background="#color/colorAccent" />
</RelativeLayout>
RecyclerAdapter:
View view = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.item_normal,
viewGroup,
false
);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
And set LinearLayoutManager:
LinearLayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false);
recyclerView.setLayoutManager(layoutManager);
Try to use a StaggeredGridLayoutManager to have different heights. Replace your GridLayoutManager with the below StaggeredGridLayoutManager
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
Related
My ReycyclerView is not showing data, but once i removed .setHasFixedSize(true), then only it will display. However, this causes another problem. On the first time entering the fragment, it works fine, my actionBar is displaying, but on the second time, it somehow overlaps or pushes away my ActionBar.
I guess .sethasFixedSize is necessary but if i keep it, it will not display data. What causes this?
First time entering:
Second time entering (before notifyItemInserted()):
After notifyItemInserted():
fragment.xml:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/cartItemRv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
fragment.kt:
onCreateView() {
binding.cartItemRv.layoutManager = LinearLayoutManager(context)
binding.cartItemRv.setHasFixedSize(true)
cartAdapter = CartAdapter(productNameList, productVariationList, cartItemList)
binding.cartItemRv.adapter = cartAdapter
//code for retrieving data from Firebase
cartAdapter.notifyItemInserted(productNameList.size-1)
}
Adapter:
class CartAdapter(...: RecyclerView.Adapter<CartAdapter.CartViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.cart_item, parent, false)
return CartViewHolder(itemView, mListener)
}
override fun onBindViewHolder(holder: CartViewHolder, position: Int) {
...
}
override fun getItemCount(): Int {
return productNameList.size
}
inner class CartViewHolder(itemView: View, listener: onItemClickListener) : RecyclerView.ViewHolder(itemView){
...
}
}
about sethasFixedSize , if the size of your the RecyclerView depends on the adapter's content you have to set the sethasFixedSize vlaue : false
otherwise set it true .
// for depending on adapter
mRecyclerView.setHasFixedSize(false);
// for doesn't depend on adapter
mRecyclerView.setHasFixedSize(true);
add NestedScrollView on the parent of RecyclerView
<?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="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/cartItemRv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"/>
</androidx.core.widget.NestedScrollView>
</RelativeLayout>
Then set RecyclerView
cartItemRv.setHasFixedSize(false);
I get a problem with my horizontal RecyclerView. I need to create RecyclerView with different width of each item. I use wrap_content for this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
android:id="#+id/recyclerItemLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardPreventCornerOverlap="false"
app:cardCornerRadius="#dimen/_10sdp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
app:cardElevation="0dp"
app:cardBackgroundColor="#android:color/darker_gray"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp">
<TextView
android:id="#+id/recyclerItemText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:textSize="#dimen/_17sdp"
android:text="test"
android:textColor="#color/colorKeyboardRecyclerViewItemText"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:layout_marginTop="7dp"
android:layout_marginBottom="7dp"/>
</androidx.cardview.widget.CardView>
But when I scroll recyclerview and get to the first element I got this:
I think it is because the adapter redraws items every time. Here is code of my adapter:
class KeyboardAdapter(private val fontsNames: FontsData, private val fontButtonCallback: (Int) -> Unit): RecyclerView.Adapter<KeyboardAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.keyboard_recyclerview_item, parent, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return fontsNames.fontsArrayEn.count()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemText.text = fontsNames.fontsArrayEn[position].name
val selectedColor = holder.itemLayout.context.resources.getColor(R.color.colorKeyboardRecyclerViewSelectedItem)
val backgroundColor = holder.itemLayout.context.resources.getColor(android.R.color.transparent)
holder.itemLayout.setOnClickListener{
fontButtonCallback(position)
changeIsSelectedState(position)
fontsNames.fontsArrayEn[position].isSelected = true
notifyDataSetChanged()
}
/* holder.itemLayout.post{ val itemHeight = holder.itemLayout.height.toFloat()
val itemRadius = itemHeight /2.5
holder.itemLayout.radius = Utils().intToDp(holder.itemLayout.context, itemRadius.toFloat())} */
if (fontsNames.fontsArrayEn[position].isSelected)
holder.itemLayout.setCardBackgroundColor(selectedColor)
else
holder.itemLayout.setCardBackgroundColor(backgroundColor)
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val itemLayout = itemView.findViewById<CardView>(R.id.recyclerItemLayout)!!
val itemText = itemView.findViewById<TextView>(R.id.recyclerItemText)!!
}
private fun changeIsSelectedState(position: Int){
for (i in 0 until fontsNames.fontsArrayEn.count()){
fontsNames.fontsArrayEn[i].isSelected = i == position
}
}
}
And i have one more question. How I can set cardCornerRadius dynamically depends of item height ?
Thanks in advance!
The TextView inside the card is the problem.
The text view is match_parent
android:layout_width="match_parent"
android:layout_height="match_parent"
But the parent is wrap_content.
Change the TextView to wrap_content and then every word is gonna be the size of the TextView and the CardView will have the size of the child.
I'm a Kotlin newbie learning how to create simple recyclerview apps. My code is supposed to list the integers 1..10 in vertically stacked cells. However, it only lists the first item. I've consulted several tutorials and reviewed my code several times(after long breaks), but I can't see anything wrong in my code.
I got the bright idea early today to print Log statements. Examining them, I note that my onBindViewHolder function is only called once. What blunder am I making?
Here is my log output:
D/QuoteAdapter: value is: 1
D/QuoteAdapter: index is: 0
D/QuoteAdapter: Size is: 10
my activity:
class MainActivity : AppCompatActivity() {
lateinit var mRecyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mRecyclerView = findViewById(R.id.recyclerView)
mRecyclerView.layoutManager = LinearLayoutManager(this)
mRecyclerView.adapter = QuoteAdapter()
//mRecyclerView.setHasFixedSize(true)
}
}
my adapter:
class QuoteAdapter : RecyclerView.Adapter<QuoteViewHolder>() {
private val listOfInts = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
private val TAG = "QuoteAdapter"
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuoteViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.recyclerview_item_row, parent, false)
return QuoteViewHolder(view)
}
override fun getItemCount(): Int {
Log.d(TAG, "Size is: ${listOfInts.size.toString()}")
return listOfInts.size
}
override fun onBindViewHolder(holder: QuoteViewHolder, position: Int) {
val item = listOfInts[position]
Log.d(TAG, "value is: ${item.toString()}")
Log.d(TAG, "index is: ${position.toString()}")
holder.listTitle.text = item.toString()
}
}
my viewholder:
class QuoteViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val listTitle = itemView.findViewById(R.id.itemString) as TextView
}
my layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/itemString"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
my main layout is shown below:
<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:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
In your "my layout" try this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/itemString"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Notice layout_height of LinearLayout has changed to wrap_content
Also doubt you need the android:orientation="vertical" on your ViewHolders item xml unless you will add more than just 1 TextView in the future.
Like Zain says, you can just use a TextView on its own in a layout file, which will also fix the problem (so long as its height is wrap_content!)
There are actually a few included with Android - type android.R.layout. and you'll see a few things, like simple_list_item_1 which is just a styled TextView (you can ctrl+click the reference or whatever to look at the file). Can be nice if you just want to make a quick thing!
The ID of the TextView in android.R.layout.simple_list_item_1 is #android:id/text1 - note the android prefix, because its part of the android resources, not your app's. Which means you have to reference the ID in the same way as the layout, with android at the front: android.R.id.text1
You can get rid of the LinearLayout in the list item layout, and only keep the TextView.
So, replace your list item layout with:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/itemString"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
I want to populate a RecyclerView with 2 different Item types,
Column in the middle should have only the BIG_ITEM and the other columns should have the SMALL_ITEM, by using GridLayoutManager with 3 columns and specifying Item Types as
position % 3 == 1 -> BIG_ITEM else SMALL_ITEM
I can achieve this but the problem is BIG_ITEM and SMALL_ITEM stays in order with the row, so SMALL_ITEM's don't fill the gap and I get this view
instead
[![enter image description here][1]][1]
I tried to use ItemDecoration to specify a constant gap between small and big tiles but it didn't work either.
If I use StaggeredGridLayout tiles wrap the gap but the order changes so I no longer have the Big tiles in the middle.
So my question is how can I achieve this view? 4 small tile height should be equal to 3 big tile height and big tiles should be in the middle. Yet the margin between tiles should be equal
[![enter image description here][2]][2]
override fun getItemViewType(position: Int): Int {
return if (position.rem(3) == 1) {
BIG_VIEW
} else {
SMALL_VIEW
}
}
Item Decoration I tried:
class ItemOffsetDecoration(private val mItemOffset: Int) : RecyclerView.ItemDecoration() {
constructor(#NonNull context: Context, #DimenRes itemOffsetId: Int) : this(context.resources.getDimensionPixelSize(itemOffsetId)) {}
override fun getItemOffsets(
outRect: Rect, view: View, parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.set(mItemOffset, mItemOffset, mItemOffset, mItemOffset)
}
}
big item:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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="wrap_content"
>
<ImageView
android:id="#+id/imageView_kids_item"
android:layout_width="500dp"
android:layout_height="266dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/icon_no_image" />
</android.support.constraint.ConstraintLayout>
small item:
<ImageView
android:id="#+id/imageView_kids_item"
android:layout_width="370dp"
android:layout_height="200dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/icon_no_image" />
What is the best strategy to achieve this feature:
I Have a horizontal RecyclerView with cards.
Each card will fulfil the entire screen, but I want it to show part of the next card and previous one if it has more than one item.
I know I can achieve this by setting my card android:layout_width at the adapter to have a specific DP like 250dp instead of match_parent.
But it doesn't look like a proper solution.
This is my code:
Activity with RecyclerView:
class ListPokemon : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val items = createListPokemons()
recyclerView.adapter = PokemonAdapter(items)
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
recyclerView.setHasFixedSize(true)
val pagerSnapHelper = PagerSnapHelper()
pagerSnapHelper.attachToRecyclerView(recyclerView)
}
private fun createListPokemons(): List<Pokemon> {
val pokemons = ArrayList<Pokemon>()
pokemons += createPokemon("Pikachu")
pokemons += createPokemon("Bulbasaur")
pokemons += createPokemon("Charmander")
pokemons += createPokemon("Squirtle")
return pokemons
}
private fun createPokemon(name: String) = Pokemon(name = name, height = 1, weight = 69, id = 1)
}
Layout of Activity:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"/>
</android.support.constraint.ConstraintLayout>
Adapter:
class PokemonAdapter(val list: List<Pokemon>) : RecyclerView.Adapter<PokemonAdapter.PokemonVH>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PokemonAdapter.PokemonVH {
return PokemonVH(LayoutInflater.from(parent.context)
.inflate(R.layout.pokemon_item, parent, false))
}
override fun onBindViewHolder(holder: PokemonAdapter.PokemonVH, position: Int) {
holder.textViewName.text = list[position].name
}
override fun getItemCount(): Int {
return list.size
}
class PokemonVH(itemView: View) : RecyclerView.ViewHolder(itemView) {
var textViewName: TextView = itemView.findViewById(R.id.textViewName)
}
}
Layout of Adapter:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
android:layout_gravity="center_horizontal"
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="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:padding="36dp"
android:id="#+id/textViewName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="22sp"
tools:text="Teste String"/>
</LinearLayout>
</android.support.v7.widget.CardView>
This is my result:
I would like to show part of the next card at this situation. How can I do this?
Thanks.
What you need to do is set padding to your RecyclerView, set clipToPadding to false, use a SnapHelper with it, and you need to make sure the margins on your cards are less than or equal to the padding in the RecylerView.
So, let's say you want the distance from the cards to the sides of the screen to be 16dp and you want the distance between the cards to be 8dp. You'll have to set the margins on each card to 4dp, so the total margin is 8dp. And you have to set the padding to 12dp, given there's already a margin of 4dp on each side of the card.
It'll look a bit like this:
Your list:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
android:clipToPadding="false"
android:orientation="horizontal"
android:paddingStart="12dp"
android:paddingEnd="12dp"/>
Your cards:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_marginStart="4dp"
app:cardElevation="2dp"/>
I think the padding solution is not a good for all cases, because forces the last item to have padding to the right.
Personally i use runtime width calculation of each item and i am very satisfied with this. So you can do the following:
onBindViewHolder
if (position == data.size - 1) {
holder.itemView.layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)
} else {
if (width == null) {
holder.itemView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
holder.itemView.viewTreeObserver.removeOnGlobalLayoutListener(this)
width = holder.itemView.width
params.width = width!! - partOfPage
holder.itemView.requestLayout()
}
})
} else {
params.width = width!! - partOfPage
holder.itemView.requestLayout()
}
}
The outcome is that all middle items are rendered showing a part of the next page, but the last one is rendered full width.
Change your CardView width from "match_parent" to "0dp". And add, layout_weight as "80" (or similar). Make your parent view (RecyclerView) layout_weightSum as "100".
android:layout_width="0dp"
android:layout_weight="80"