Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView in ConstraintLayout. Show only complety visible items on a screen

I need to create a horizontal list of items that only displays fully visible items. enter image description here

But as you can see, my recycler view show a particular element. I use a horizontal LinearLayoutManager.

I add 10 elements, but recycler view has room only for 3. I need to show only 3, but it always show me 3 and particular element.

<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">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintEnd_toStartOf="@+id/textView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

My item layout:

<LinearLayout
    android:id="@+id/itemLayout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="10dp">

    <TextView
        android:id="@+id/tvAnimalName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ASDAS"
        android:background="@color/colorAccent"
        android:padding="10dp"
        android:textSize="17sp"/>

</LinearLayout>

Adapter and activity are plain.

How can I show only visible 3 items?

Edit. I must to disable scroll. So i am using:

layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false) {
            @Override
            public boolean canScrollHorizontally() {
                return false;
            }
        };

Edit 2. These methods show -1 always:

int findLastVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();
like image 810
Oleg Skidan Avatar asked Dec 20 '25 19:12

Oleg Skidan


2 Answers

class HideLastDecorator() : RecyclerView.ItemDecoration() {

override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
    super.onDraw(c, parent, state)
    val count = parent.childCount
    for (i in 0 until count) {
        parent.getChildAt(i).visibility = if (count == i - 1) View.INVISIBLE else View.VISIBLE 
    }
}
}

and add it to your recyclerView Decorations

appsRecyclerView.addItemDecoration(HideLastDecorator())

Sorry for Kotlin :)

View.INVISIBLE is important, because if the View becomes GONE, it will be removed from the measuring of the RecyclerView's content and the new ViewHolder would be added.

I prefer to work careful with OnClickListener if any is set for the ViewHolder's content.

like image 167
RelaxedSoul Avatar answered Dec 23 '25 11:12

RelaxedSoul


Below code will work for you. A little explanation: Extend RecyclerView and override onLayout() method. Once RecyclerView is ready iterate through all visible (on-screen) children of RecyclerView and apply your logic. In our case we'll draw BounddingBox for every nth child and RecyclerView. If child's bounds lie inside RecyclerView's bounds then show that child otherwise set visibility to GONE/INVISIBLE.

public class CustomRecyclerView extends RecyclerView {
    Rect recyclerViewBounds = new Rect();
    Rect currentChildViewBounds = new Rect();

    public CustomRecyclerView(@NonNull Context context) {
        super(context);
    }

    public CustomRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        recyclerViewBounds.set(l, t, r, b);

        for (int i = 0; i < getChildCount(); i++) {
            View currentChild = getChildAt(i);

            currentChildViewBounds.set(currentChild.getLeft(), currentChild.getTop(), currentChild.getRight(), currentChild.getBottom());
            currentChild.setVisibility(recyclerViewBounds.contains(currentChildViewBounds) ? VISIBLE : GONE);  // or INVISBLE instead of GONE
        }
    }
}

And most importantly: In your xml file use com.your.packagename.CustomRecyclerView instead of androidx.recyclerview.widget.RecyclerView.

NOTE: Please refrain from any object initialization inside onLayout(). What I mean is don't move the object initializations inside onLayout() to make it "fancier".

like image 35
Farid Avatar answered Dec 23 '25 10:12

Farid