Android GridLayoutManager示例

时间:2020-02-23 14:28:58  来源:igfitidea点击:

Android GridLayoutManager是RecyclerView.LayoutManager的实现,用于对网格中的项目进行布局。
在本教程中,我们将创建一个应用程序,该应用程序以GridLayout的形式在RecyclerView内显示CardViews。
另外,我们将实现一个接口,使RecyclerView项目单击类似于ListView itemClickListener

Android GridLayoutManager

我们在这里使用LinearLayoutManager实现了RecyclerView。
现在,让我们使用" GridLayoutManager"将RecyclerView布局为网格。

以下是GridLayoutManager的构造函数。

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

reverseLayout如果设置为true,则从头到尾布局项目。

要设置每个项目的跨度大小,我们在GridLayoutManager上调用方法setSpanSizeLookup

让我们在新的Android Studio项目中使用GridLayoutManager实现RecyclerView。

Android GridLayoutManager示例项目结构

该项目由单个Activity:MainActivity.java,适配器类RecyclerViewAdapter.java,DataModel.java类和自定义GridLayoutManager类AutoFitGridLayoutManager.java组成。

MainActivity.java类的xml布局在文件" 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>

注意:不要忘记在build.gradle文件中为Material Design小部件和CardView添加以下依赖项。

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

下面给出了DataModel.java类:package com.theitroad.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类将保存每个项目单元格的文本,可绘制图标和背景颜色。

RecyclerViewAdapter.java类如下所示:

package com.theitroad.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类中实现。

每个RecyclerView项的xml布局如下。
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.theitroad.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);
  }
}

跨度计数是根据可用的方向,宽度和高度动态计算的。

MainActivity.java类如下:

package com.theitroad.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();

  }
}
  • 上面的类实现了接口RecyclerViewAdapter.ItemListener,并覆盖了适配器类中定义的方法onItemClick。
    通过这样做,我们在Activity中实现了RecyclerView Click Listener而不是Adapter类(类似于为ListView定义的标准onItemClickListener)
  • DataModel类保存每个RecyclerView项的详细信息
  • 可以通过实例化列宽度设置为500的AutoFitGridLayoutManager类或者通过调用GridLayoutManager类对象并将列数设置为2来定义RecyclerView的LayoutManager。

让我们看看带有标准GridLayoutManager代码的应用程序的输出。

如您所见,每一行都有两个在两个方向上都跨越列宽的项目。

现在注释掉简单GridLayoutManager的代码,并运行AutoFitGridLayoutManager的代码

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

实际应用程序的输出如下。

从上面的输出中可以看到,当方向更改为横向时,每行都有三项,从而动态调整项目的大小以自动适应列宽。