Пример Android GridLayoutManager

Android GridLayoutManager – это реализация RecyclerView.LayoutManager для размещения элементов в сетке. В этом уроке мы создадим приложение, отображающее CardViews внутри RecyclerView в виде GridLayout. Также мы реализуем интерфейс, делающий клик по элементу RecyclerView подобным ListView с использованием itemClickListener.

Android GridLayoutManager

Мы реализовали RecyclerView с использованием LinearLayoutManager здесь. Теперь давайте используем GridLayoutManager, чтобы разместить RecyclerView в виде сетки. Вот конструктор для GridLayoutManager.

GridLayoutManager (Context context, 
                int spanCount, 
                int orientation, 
                boolean reverseLayout)

Если reverseLayout установлен в true, то элементы размещаются с конца к началу. Чтобы установить размер ячейки для каждого элемента, мы вызываем метод setSpanSizeLookup на GridLayoutManager. Давайте реализуем RecyclerView с использованием GridLayoutManager в новом проекте Android Studio.

Пример структуры проекта Android GridLayoutManager

Проект состоит из одной активности: MainActivity.java, класса адаптера: RecyclerViewAdapter.java, класса DataModel.java и пользовательского класса GridLayoutManager AutoFitGridLayoutManager.java. Макет XML для класса MainActivity.java определен в файле activity_main.xml как

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    </RelativeLayout>

</android.support.design.widget.CoordinatorLayout>

Примечание: Не забудьте добавить следующие зависимости для виджетов Material Design и CardView в файл build.gradle.

compile 'com.android.support:cardview-v7:25.1.1'
compile 'com.android.support:design:25.1.1'

Класс DataModel.java приведен ниже: package com.journaldev.recyclerviewgridlayoutmanager;

public class DataModel {

    public String text;
    public int drawable;
    public String color;

    public DataModel(String t, int d, String c )
    {
        text=t;
        drawable=d;
        color=c;
    }
}

Класс DataModel будет содержать текст, значок drawable и цвет фона каждой ячейки элемента. Класс RecyclerViewAdapter.java приведен ниже:

package com.journaldev.recyclerviewgridlayoutmanager;

import android.content.Context;
import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.ArrayList;


public class RecyclerViewAdapter extends RecyclerView.Adapter {

    ArrayList mValues;
    Context mContext;
    protected ItemListener mListener;

    public RecyclerViewAdapter(Context context, ArrayList values, ItemListener itemListener) {

        mValues = values;
        mContext = context;
        mListener=itemListener;
    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        public TextView textView;
        public ImageView imageView;
        public RelativeLayout relativeLayout;
        DataModel item;

        public ViewHolder(View v) {

            super(v);

            v.setOnClickListener(this);
            textView = (TextView) v.findViewById(R.id.textView);
            imageView = (ImageView) v.findViewById(R.id.imageView);
            relativeLayout = (RelativeLayout) v.findViewById(R.id.relativeLayout);

        }

        public void setData(DataModel item) {
            this.item = item;

            textView.setText(item.text);
            imageView.setImageResource(item.drawable);
            relativeLayout.setBackgroundColor(Color.parseColor(item.color));

        }


        @Override
        public void onClick(View view) {
            if (mListener != null) {
                mListener.onItemClick(item);
            }
        }
    }

    @Override
    public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_view_item, parent, false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder Vholder, int position) {
        Vholder.setData(mValues.get(position));

    }

    @Override
    public int getItemCount() {

        return mValues.size();
    }

    public interface ItemListener {
        void onItemClick(DataModel item);
    }
}

В приведенном выше коде мы определили интерфейс ItemListener, который будет реализован в классе MainActivity.java. Макет XML для каждого элемента RecyclerView приведен ниже. recycler_view_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:card_view="https://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <android.support.v7.widget.CardView
        android:id="@+id/cardView"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        card_view:cardCornerRadius="0dp"
        card_view:cardElevation="@dimen/margin10"
        card_view:cardMaxElevation="@dimen/margin10"
        card_view:contentPadding="@dimen/margin10">


        <RelativeLayout
            android:id="@+id/relativeLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_gravity="center">

            <ImageView
                android:id="@+id/imageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:tint="@android:color/white"
                android:padding="5dp" />


            <TextView
                android:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:textColor="@android:color/white"
                android:layout_below="@+id/imageView" />


        </RelativeLayout>

    </android.support.v7.widget.CardView>

</LinearLayout>

Класс AutoFitGridLayoutManager.java приведен ниже:

package com.journaldev.recyclerviewgridlayoutmanager;

import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;

public class AutoFitGridLayoutManager extends GridLayoutManager {

    private int columnWidth;
    private boolean columnWidthChanged = true;

    public AutoFitGridLayoutManager(Context context, int columnWidth) {
        super(context, 1);

        setColumnWidth(columnWidth);
    }

    public void setColumnWidth(int newColumnWidth) {
        if (newColumnWidth > 0 && newColumnWidth != columnWidth) {
            columnWidth = newColumnWidth;
            columnWidthChanged = true;
        }
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (columnWidthChanged && columnWidth > 0) {
            int totalSpace;
            if (getOrientation() == VERTICAL) {
                totalSpace = getWidth() - getPaddingRight() - getPaddingLeft();
            } else {
                totalSpace = getHeight() - getPaddingTop() - getPaddingBottom();
            }
            int spanCount = Math.max(1, totalSpace / columnWidth);
            setSpanCount(spanCount);
            columnWidthChanged = false;
        }
        super.onLayoutChildren(recycler, state);
    }
}

Количество элементов span рассчитывается динамически на основе ориентации, доступной ширины и высоты. Класс MainActivity.java приведен ниже:

package com.journaldev.recyclerviewgridlayoutmanager;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity implements RecyclerViewAdapter.ItemListener {

    RecyclerView recyclerView;
    ArrayList arrayList;

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


        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        arrayList = new ArrayList();
        arrayList.add(new DataModel("Item 1", R.drawable.battle, "#09A9FF"));
        arrayList.add(new DataModel("Item 2", R.drawable.beer, "#3E51B1"));
        arrayList.add(new DataModel("Item 3", R.drawable.ferrari, "#673BB7"));
        arrayList.add(new DataModel("Item 4", R.drawable.jetpack_joyride, "#4BAA50"));
        arrayList.add(new DataModel("Item 5", R.drawable.three_d, "#F94336"));
        arrayList.add(new DataModel("Item 6", R.drawable.terraria, "#0A9B88"));

        RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, arrayList, this);
        recyclerView.setAdapter(adapter);


        /**
         AutoFitGridLayoutManager that auto fits the cells by the column width defined.
         **/

        /*AutoFitGridLayoutManager layoutManager = new AutoFitGridLayoutManager(this, 500);
        recyclerView.setLayoutManager(layoutManager);*/


        /**
         Simple GridLayoutManager that spans two columns
         **/
        GridLayoutManager manager = new GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(manager);
    }

    @Override
    public void onItemClick(DataModel item) {

        Toast.makeText(getApplicationContext(), item.text + " is clicked", Toast.LENGTH_SHORT).show();

    }
}

  1. Вышеупомянутый класс реализует интерфейс RecyclerViewAdapter.ItemListener и переопределяет метод onItemClick, определенный в классе адаптера. Таким образом, мы реализовали слушатель кликов RecyclerView внутри нашей активности, а не в классе адаптера (аналогично стандартному onItemClickListener, определенному для ListView)
  2. A DataModel class holds the details for each RecyclerView item
  3. LayoutManager RecyclerView можно определить либо, создав экземпляр класса AutoFitGridLayoutManager с шириной столбца, установленной как 500, либо вызвав объект класса GridLayoutManager и установив количество столбцов равным 2

Давайте посмотрим на вывод приложения с стандартным кодом GridLayoutManager. Как видите, каждая строка содержит два элемента, которые занимают всю ширину столбца в обеих ориентациях. Теперь закомментируйте код для простого GridLayoutManager и запустите код для AutoFitGridLayoutManager

AutoFitGridLayoutManager layoutManager = new AutoFitGridLayoutManager(this, 500);
recyclerView.setLayoutManager(layoutManager);

Вот вывод приложения в действии. Как видно из вышеприведенного вывода, при изменении ориентации на альбомную каждая строка содержит три элемента, что динамически подстраивает их размеры для автоматического соответствия ширине столбца. Этим завершается данное руководство. Вы можете скачать окончательный проект Android GridLayoutManager по ссылке ниже.

Загрузить проект Android GridLayoutManager

Source:
https://www.digitalocean.com/community/tutorials/android-gridlayoutmanager-example