39

I am trying to create this effect

Design image

I am using a recycler view but my issue, is that each card is 100% of the width of the screen as apposed to 70%.

Here is the xml code for each item

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rowLayout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/scale_20dp">

    <LinearLayout
        android:id="@+id/button_parent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <android.support.v7.widget.CardView
            android:id="@+id/card_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <LinearLayout
                android:id="@+id/currentYear"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:background="@drawable/paymentscreengrey"
                android:gravity="center"
                android:orientation="vertical"
                android:paddingLeft="35dp"
                android:paddingTop="@dimen/scale_50dp">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/scale_20dp"
                    android:text="****   ****   ****   5432"
                    android:textColor="@color/white"
                    android:textSize="@dimen/scale_20dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="2345"
                    android:textColor="@color/white"
                    android:textSize="@dimen/scale_16dp" />
fdermishin
  • 3,519
  • 3
  • 24
  • 45
Adam Katz
  • 6,999
  • 11
  • 42
  • 74

7 Answers7

38

If you want the first item to be left-aligned (i.e., reproduce what's in the screenshot), subclass LinearLayoutManager and override the three generate*LayoutParams methods. Here's how I did it: https://gist.github.com/bolot/6f1838d29d5b8a87b5fcadbeb53fb6f0.

class PeekingLinearLayoutManager : LinearLayoutManager {
    @JvmOverloads
    constructor(context: Context?, @RecyclerView.Orientation orientation: Int = RecyclerView.VERTICAL, reverseLayout: Boolean = false) : super(context, orientation, reverseLayout)

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)

    override fun generateDefaultLayoutParams() =
        scaledLayoutParams(super.generateDefaultLayoutParams())

    override fun generateLayoutParams(lp: ViewGroup.LayoutParams?) =
        scaledLayoutParams(super.generateLayoutParams(lp))

    override fun generateLayoutParams(c: Context?, attrs: AttributeSet?) =
        scaledLayoutParams(super.generateLayoutParams(c, attrs))

    private fun scaledLayoutParams(layoutParams: RecyclerView.LayoutParams) =
        layoutParams.apply {
            when(orientation) {
                HORIZONTAL -> width = (horizontalSpace * ratio).toInt()
                VERTICAL -> height = (verticalSpace * ratio).toInt()
            }
        }

    private val horizontalSpace get() = width - paddingStart - paddingEnd

    private val verticalSpace get() = height - paddingTop - paddingBottom

    private val ratio = 0.9f // change to 0.7f for 70%
}

This solution is based on/inspired by the spanning (i.e., fit all items to screen) linear layout manager https://gist.github.com/heinrichreimer/39f9d2f9023a184d96f8.

Btw, if you just want to show the items to the left and to the right, while the current item is centered, you can add padding to the recycler view and set clipToPadding to false. In this case you don't even need a custom layout manager.

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:paddingStart="16dp"
    android:paddingEnd="16dp"
    android:clipToPadding="false"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager">
tinsukE
  • 930
  • 9
  • 20
bolot
  • 2,854
  • 2
  • 18
  • 15
24

I needed to have the items in my horizontal RecyclerView to be 70% of the width of the recyclerview. It can be easily done in onCreateViewHolder():

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.row, parent, false);
        view.layoutParams = ViewGroup.LayoutParams((parent.width * 0.7).toInt(),ViewGroup.LayoutParams.MATCH_PARENT)
        return ViewHolder(view);
    }

Result

Peterdk
  • 15,625
  • 20
  • 101
  • 140
11

Two ways of doing this really.

1)Use a custom view for your the recycled view. Override onMeasure to return its width as 70 percent of the screen.

2)In your Recycler View adapter, when you create the view set its width to be 70 percent of the screen's width.

In either case you get the screen size from the Display and just multiply the width by .7. In the first case you set that as the EXACT measured width, in the second you set it in the layout param. The second is probably a bit easier.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • I tried 2 and it never worked, although it resized the size of the view all the items on the bottom and left of the item dissapeared off the screen. Would I not face the same problem if i tried your first answer? – Adam Katz Jul 29 '16 at 08:09
8

I had a similar issue where I had a fragment with a horizontal RecyclerView and wanted each view item's width to be a third of the user's screen. Solved it by adding the following in the constructor of our ViewHolder class (in my case I wanted each view holder to be 1/3 of the screen instead of 70%):

    private class OurViewHolder extends RecyclerView.ViewHolder {
        ...

        public OurViewHolder (LayoutInflater inflater, ViewGroup parent) {
            super (inflater.inflate (R.layout.list_item_layout, parent, false));

            // This code is used to get the screen dimensions of the user's device
            DisplayMetrics displayMetrics = new DisplayMetrics();
            getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
            int width = displayMetrics.widthPixels;
            int height = displayMetrics.heightPixels;

            // Set the ViewHolder width to be a third of the screen size, and height to wrap content
            itemView.setLayoutParams(new RecyclerView.LayoutParams(width/3, RecyclerView.LayoutParams.WRAP_CONTENT));

            ...
        }

        ...
sbearben
  • 323
  • 6
  • 16
0

for your row.xml parent, you must use wrap_content for its width then add this property.

android:paddingLeft="25dp"

You will get same result

Mostafa Anter
  • 3,445
  • 24
  • 26
0

Just updated a bit from this answer by adding a margin and getting displayMetrics from the resources to make it clean:

inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        fun bind(product: StyleMaster) = with(itemView) {
            val width = context.resources.displayMetrics?.widthPixels
            if (width != null) {
                val params = RecyclerView.LayoutParams(width / 2, RecyclerView.LayoutParams.WRAP_CONTENT)
                params.setMargins(2, 2, 2, 2)
                itemView.layoutParams = params
            }
// Rest of the code goes here...
Shailendra Madda
  • 20,649
  • 15
  • 100
  • 138
-6

Try changing LinearLayout with PercentRelativeLayout to "wrap" the RecyclerView and then set the its width to 70%.

Change this:

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/rv"
        />

</LinearLayout>

With this:

<android.support.percent.PercentRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            app:layout_widthPercent="70%"
            android:id="@+id/rv"
            />

EDIT

Since Percent Support Library comes along with Android Support Library 23 so please make sure that you update Android Support Library in SDK Manager to the latest version already (actually 24). And then add a dependency like below in build.gradle file:

compile 'com.android.support:percent:24.0.0'
eldivino87
  • 1,425
  • 1
  • 17
  • 30
  • Unfortuanately that never worked, it just made the recycler view 70% of the width instead of the items inside of it Did you look at the picture I added to show what I am looking for? – Adam Katz Jul 29 '16 at 12:50