bryant
bryant

Reputation: 2051

Android RecyclerView ItemDecorator: align Inset Divider with List Item TextView

I would like to inset a RecyclerView ItemDecorator divider to left align with a TextView (the item title) inside the list element that is constrained to be 72dp from the parent left side. Something like we see here in the Google Material Design Docs. I assume that I need to somehow reference the layout params on the titleTextView, but am not sure how to do that from my ItemDecorator code, as I seem to be able to only get the params which is the ConstraintLayout, and not the textview itself. Any help or pointers in the right direction would be greatly appreciated! The relevant ItemDecorator code, where I try to get the textView param looks something like this:

        for (int i = 0; i < recyclerView.getChildCount() - 1; ++i) {
            View child = recyclerView.getChildAt(i);
            RecyclerView.LayoutParams params =(RecyclerView.LayoutParams) child.getLayoutParams();
//this just gives me the constraint layout, not the TextView params, how to reference the textViewParams!?

The RecyclerView looks like this:

        <android.support.v7.widget.RecyclerView
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/myList"
        android:name="com.example.Something"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layoutManager="LinearLayoutManager"
        tools:context=".controllers.fragments.ExampleFragment"
        tools:listitem="@layout/fragment_something"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

The list item xml is a constraint layout with some TextViews, and the relevant portion looks like this:

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="72dp">

    <ImageView
        android:id="@+id/myImageView"
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:layout_marginLeft="16dp"
        app:layout_constraintLeft_toLeftOf="parent"
        tools:src="@drawable/ic_menu_manage"
        android:src="@drawable/ic_menu_manage"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="16dp" />

    <TextView
        android:id="@+id/titleTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="4dp"
        android:layout_marginLeft="72dp"
        android:layout_marginTop="20dp"
        android:text="MyTitle"
        android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
        android:textStyle="bold"
        app:layout_constraintBottom_toTopOf="@+id/textView5"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="SampleTitle" />

    ...

    </android.support.constraint.ConstraintLayout>

Upvotes: 0

Views: 1323

Answers (3)

jL4
jL4

Reputation: 1242

Since you already know by how much you have to inset the divider from the left side (calculate it from your layout if you don't know), all you need to do is convert that dp value to px as shown here and set it as the left bound in your custom ItemDecoration.

public class InsetDividerDecoration extends RecyclerView.ItemDecoration {

    private final int insetValueInDp = 72; // in your case

    @Override
    public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
        int dividerLeft = (int) (insetValueInDp * Resources.getSystem().getDisplayMetrics().density);

        ...
    }
}

And use it in your recycler view -

recyclerView.addItemDecoration(new InsetDividerDecoration());

Upvotes: 0

bryant
bryant

Reputation: 2051

Since the ConstraintLayout is a ViewGroup, it is possible to access the child of the ConstraintLayout from inside of the ItemDecorator by simply doing something like:

public class MyItemDivider extends RecyclerView.ItemDecoration {

....some code here


@Override
public void onDrawOver(Canvas canvas, RecyclerView recyclerView,
                       RecyclerView.State state) {
    super.onDrawOver(canvas, recyclerView, state);

    for (int i = 0; i < recyclerView.getChildCount() - 1; ++i) {
        ViewGroup item = (ViewGroup) recyclerView.getChildAt(i);

        //for now the titleText is at index 1 of constraint layout
        TextView titleChild =  (TextView) item.getChildAt(1);
        int titleTextLeftMargin = titleChild.getLeft();

        //this would probably be less brittle 
        //but I would need to somehow change the context for this to be doable?
        //View titleChild = item.findViewById(R.id.contractListProductNameTextView);
        ...some more code here

            divider.setBounds(titleTextLeftMargin, top, right, bottom);
            divider.draw(canvas);
        }
    }
}

Upvotes: 0

Arutha
Arutha

Reputation: 21

use a custom item decorator.

class CustomItemDecoration(context: Context) : RecyclerView.ItemDecoration()
{

    private val mDivider: Drawable = context.resources.getDrawable(R.drawable.custom_item_divider) // this is a shape   that i want to use

    override fun onDrawOver(c: Canvas,
                            parent: RecyclerView,
                            state: RecyclerView.State)
    {
        val left = parent.paddingLeft // change to how much padding u want to add here .  
        val right = parent.width - parent.paddingRight

        val childCount = parent.childCount
        for (i in 0 until childCount)
        {
            val child = parent.getChildAt(i)

            val params = child.layoutParams as RecyclerView.LayoutParams

            val top = child.bottom + params.bottomMargin
            val bottom = top + mDivider.intrinsicHeight

            mDivider.setBounds(left, top, right, bottom)
            mDivider.draw(c)
        }
    }
}

you set it like that

recyclerView.addItemDecoration(CustomItemDecoration(context))

Upvotes: 2

Related Questions