Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infinite scroll of finite items

I have a GridView that has items inside 5x50.

I need to scroll them in all directions and instead of stopping when reached the end just start from the top/left.

for example left-to-right scroll

before scroll

1 2 3 4 5
6 7 8 9 10

after scroll to the right

5 1 2 3 4
10 6 7 8 9

and for top-to-bottom (or bottom-to-top)

before scroll to the bottom

1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

after scroll

6 7 8 9 10
11 12 13 14 15
1 2 3 4 5

I try to make it smooth scroll as GridView native scroll.

like image 888
CBeTJlu4ok Avatar asked Nov 11 '17 21:11

CBeTJlu4ok


1 Answers

Having specified following view hierarchy in activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

And a basic list item - a TextView, inside item.xml:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"/>

Then in the activity:

public class MainActivity extends AppCompatActivity {

    private static final int spanCount = 5;
    private static final int totalItemCount = 15;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = findViewById(R.id.recycler);
        // Shamelessly stolen from devunwired bit.ly/2yCqVIp
        recyclerView.addItemDecoration(new GridDividerDecoration(this));
        recyclerView.setLayoutManager(new GridLayoutManager(this, spanCount, LinearLayoutManager.VERTICAL, false));
        recyclerView.setAdapter(new MyAdapter(totalItemCount));
    }

    static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {

        private final int totalSizeOfItems;
        private boolean hasBeenSetup = false;

        MyAdapter(int totalSizeOfItems) {
            this.totalSizeOfItems = totalSizeOfItems;
        }

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
            final int cellSize = parent.getMeasuredWidth() / spanCount;
            view.setMinimumWidth(cellSize);
            view.setMinimumHeight(cellSize);
            setupRecyclerHeightIfNeeded(parent, cellSize);
            return new MyViewHolder(view);
        }

        // We need to perform this operation once, not each time `onCreateViewHolder` is called
        private void setupRecyclerHeightIfNeeded(View parent, int cellSize) {
            if (hasBeenSetup) return;
            hasBeenSetup = true;
            ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) parent.getLayoutParams();
            int numOfRows = (int) (totalItemCount / (double) spanCount);
            params.height = numOfRows * cellSize;
            new Handler().post(parent::requestLayout);
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, int pos) {
            int position = holder.getAdapterPosition() % totalSizeOfItems;
            holder.textView.setText(Integer.toString(position + 1));
        }

        @Override
        public int getItemCount() {
            // this will result the list to be "infinite"
            return Integer.MAX_VALUE;
        }
    }

    static class MyViewHolder extends RecyclerView.ViewHolder {

        TextView textView;

        MyViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView;
        }
    }
}

On output you'll get:

enter image description here

Taking care of the horizontal scroll would require a small amount of changes:

  • orientation of GridLayoutManager should be changed to HORIZONTAL
  • inside adapter appropriate width/height setters should be substituted

Other than that - everything should be similar.

like image 61
azizbekian Avatar answered Sep 20 '22 14:09

azizbekian