Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show part of next/previous card RecyclerView

What is the best strategy to achieve this feature:

enter image description here

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:

enter image description here

I would like to show part of the next card at this situation. How can I do this?

Thanks.

like image 279
leonvian Avatar asked Jul 12 '18 04:07

leonvian


People also ask

How do I remove a space between two items in RecyclerView?

Try to use cardElevation=0dp. This should remove the extra spacing between recyclerview items.

How do you use card view in recycler view?

Card Layout: A card Layout is used to display a list of data. It is the design of a single item of our RecyclerView. For creating a Card Layout navigate to the app > res > layout > Right-Click on it > New > Layout Resource File > Give a name to it(here card_layout).

What is LinearLayoutManager in RecyclerView?

RecyclerView provides these built-in layout managers: LinearLayoutManager shows items in a vertical or horizontal scrolling list. GridLayoutManager shows items in a grid. StaggeredGridLayoutManager shows items in a staggered grid.


2 Answers

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"/>
like image 53
Rodolfo Avatar answered Oct 20 '22 01:10

Rodolfo


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.

like image 43
mspapant Avatar answered Oct 20 '22 02:10

mspapant