【问题标题】:Simple Android grid example using RecyclerView with GridLayoutManager (like the old GridView)使用带有 GridLayoutManager 的 RecyclerView 的简单 Android 网格示例(如旧的 GridView)
【发布时间】:2017-03-27 23:56:05
【问题描述】:

我知道RecyclerView 已经取代了旧的ListViewGridView 的功能。我正在寻找一个非常基本的示例,该示例显示使用RecyclerView 的最小网格设置。我不是在寻找长篇教程风格的解释,只是一个最小的例子。我想模仿旧 GridView 的最简单的网格将包含以下功能:

  • 每行多个单元格
  • 每个单元格中的单个视图
  • 响应点击事件

【问题讨论】:

    标签: android gridview android-recyclerview gridlayoutmanager


    【解决方案1】:

    简答

    对于那些已经熟悉setting up a RecyclerView to make a list 的人来说,好消息是制作网格大致相同。当您设置RecyclerView 时,您只需使用GridLayoutManager 而不是LinearLayoutManager

    recyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
    

    如果您需要更多帮助,请查看以下示例。

    完整示例

    以下是一个类似于下图的最小示例。

    从一个空的活动开始。您将执行以下任务来添加RecyclerView 网格。您需要做的就是复制并粘贴每个部分的代码。稍后您可以对其进行自定义以满足您的需求。

    • 向 gradle 添加依赖项
    • 为活动和网格单元添加 xml 布局文件
    • 制作 RecyclerView 适配器
    • 在您的活动中初始化 RecyclerView

    更新 Gradle 依赖项

    确保您的应用程序gradle.build 文件中有以下依赖项:

    compile 'com.android.support:appcompat-v7:27.1.1'
    compile 'com.android.support:recyclerview-v7:27.1.1'
    

    您可以将版本号更新为the most current

    创建活动布局

    RecyclerView 添加到您的 xml 布局中。

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        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/rvNumbers"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    </RelativeLayout>
    

    创建网格单元布局

    RecyclerView 网格中的每个单元格将只有一个 TextView。创建一个新的布局资源文件。

    recyclerview_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:padding="5dp"
        android:layout_width="50dp"
        android:layout_height="50dp">
    
            <TextView
                android:id="@+id/info_text"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center"
                android:background="@color/colorAccent"/>
    
    </LinearLayout>
    

    创建适配器

    RecyclerView 需要一个适配器来用您的数据填充每个单元格中的视图。创建一个新的 java 文件。

    MyRecyclerViewAdapter.java

    public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
    
        private String[] mData;
        private LayoutInflater mInflater;
        private ItemClickListener mClickListener;
    
        // data is passed into the constructor
        MyRecyclerViewAdapter(Context context, String[] data) {
            this.mInflater = LayoutInflater.from(context);
            this.mData = data;
        }
    
        // inflates the cell layout from xml when needed
        @Override
        @NonNull 
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = mInflater.inflate(R.layout.recyclerview_item, parent, false);
            return new ViewHolder(view);
        }
    
        // binds the data to the TextView in each cell
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.myTextView.setText(mData[position]);
        }
    
        // total number of cells
        @Override
        public int getItemCount() {
            return mData.length;
        }
    
    
        // stores and recycles views as they are scrolled off screen
        public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
            TextView myTextView;
    
            ViewHolder(View itemView) {
                super(itemView);
                myTextView = itemView.findViewById(R.id.info_text);
                itemView.setOnClickListener(this);
            }
    
            @Override
            public void onClick(View view) {
                if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
            }
        }
    
        // convenience method for getting data at click position
        String getItem(int id) {
            return mData[id];
        }
    
        // allows clicks events to be caught
        void setClickListener(ItemClickListener itemClickListener) {
            this.mClickListener = itemClickListener;
        }
    
        // parent activity will implement this method to respond to click events
        public interface ItemClickListener {
            void onItemClick(View view, int position);
        }
    }
    

    注意事项

    • 虽然不是绝对必要的,但我包含了用于侦听单元格上的单击事件的功能。这在旧的GridView 中可用,是一种常见的需求。如果不需要,可以删除此代码。

    在Activity中初始化RecyclerView

    将以下代码添加到您的主要活动中。

    MainActivity.java

    public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener {
    
        MyRecyclerViewAdapter adapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // data to populate the RecyclerView with
            String[] data = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48"};
    
            // set up the RecyclerView
            RecyclerView recyclerView = findViewById(R.id.rvNumbers);
            int numberOfColumns = 6;
            recyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
            adapter = new MyRecyclerViewAdapter(this, data);
            adapter.setClickListener(this);
            recyclerView.setAdapter(adapter);
        }
    
        @Override
        public void onItemClick(View view, int position) {
            Log.i("TAG", "You clicked number " + adapter.getItem(position) + ", which is at cell position " + position);
        }
    }
    

    注意事项

    • 请注意,该活动实现了我们在适配器中定义的ItemClickListener。这使我们能够处理onItemClick 中的单元格点击事件。

    完成

    就是这样。您现在应该能够运行您的项目并获得类似于顶部图像的内容。

    进行中

    圆角

    自动调整列

    进一步研究

    【讨论】:

    • @MarianPaździoch,是的,我只是把它作为一个最小的例子。它绝对可以使用一些美化工作。我会在以后的某个时间尝试更新这个答案。
    • 我登录只是为了指出像你这样的人一直保持这个门户网站的活力和踢球。我在看到这个解决方案之前被困在这个问题上两天。非常感谢
    • @androiddeveloper,网格项目从左到右、从上到下排列。当项目多于屏幕无法容纳时,滚动是垂直的。
    • 未来的读者,让我为您节省一些时间,关键是recyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
    • @daka,说得好。我编辑了我的答案,将其包含在开头。
    【解决方案2】:

    虽然我喜欢并欣赏Suragch's answer,但我想留下一个说明,因为我发现编写Adapter (MyRecyclerViewAdapter) 来定义和公开Listener 方法onItemClick 是由于没有正确使用类封装,这不是最好的方法。所以我的建议是让 Adapter 单独处理 Listening 操作(这是他的目的!)并将这些操作与使用 Adapter 的 Activity 分开(MainActivity)。所以这就是我设置适配器类的方式:

    MyRecyclerViewAdapter.java

    public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
    
        private String[] mData = new String[0];
        private LayoutInflater mInflater;
    
        // Data is passed into the constructor
        public MyRecyclerViewAdapter(Context context, String[] data) {
            this.mInflater = LayoutInflater.from(context);
            this.mData = data;
        }
    
        // Inflates the cell layout from xml when needed
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = mInflater.inflate(R.layout.recyclerview_item, parent, false);
            ViewHolder viewHolder = new ViewHolder(view);
            return viewHolder;
        }
    
        // Binds the data to the textview in each cell
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            String animal = mData[position];
            holder.myTextView.setText(animal);
        }
    
        // Total number of cells
        @Override
        public int getItemCount() {
            return mData.length;
        }
    
        // Stores and recycles views as they are scrolled off screen
        public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
            public TextView myTextView;
    
            public ViewHolder(View itemView) {
                super(itemView);
                myTextView = (TextView) itemView.findViewById(R.id.info_text);
                itemView.setOnClickListener(this);
            }
    
            @Override
            public void onClick(View view) {
                onItemClick(view, getAdapterPosition());
            }
        }
    
        // Convenience method for getting data at click position
        public String getItem(int id) {
            return mData[id];
        }
    
        // Method that executes your code for the action received
        public void onItemClick(View view, int position) {
            Log.i("TAG", "You clicked number " + getItem(position).toString() + ", which is at cell position " + position);
        }
    }
    

    请注意现在在MyRecyclerViewAdapter 中定义的onItemClick 方法,这是您希望为收到的事件/操作编写任务的地方。

    为了完成这个转换,只需要做一个小改动:Activity 不再需要实现 MyRecyclerViewAdapter.ItemClickListener,因为现在这完全由 适配器。这将是最后的修改:

    MainActivity.java

    public class MainActivity extends AppCompatActivity {
    
        MyRecyclerViewAdapter adapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // data to populate the RecyclerView with
            String[] data = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48"};
    
            // set up the RecyclerView
            RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rvNumbers);
            int numberOfColumns = 6;
            recyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
            adapter = new MyRecyclerViewAdapter(this, data);
            adapter.setClickListener(this);
            recyclerView.setAdapter(adapter);
        }
    }
    

    【讨论】:

    • 如果activity确实需要监听点击事件怎么办?例如将数据传递给演示者,根据单击的项目、跟踪等执行一些逻辑。
    • 我同意 Adapter 应该处理点击事件,因为它有包含数据的项目。 @AhmadFadli 如果您需要在适配器的主机(片段或活动)中做一些工作,您应该使用您需要的方法创建一个回调接口。你的主机实现了这个接口。然后将主机实例传递给适配器的构造函数。拥有主机实例,您可以在需要时从适配器调用它的方法。您的主机我们会收到回调。这通常在您需要使用 ActionMode 时使用。当您长按选择项目并使用 ActionBar 按钮时。
    • 我不同意,认为点击事件应该在托管Activity中处理。因为只有点击监听器才能知道Activity视图和其他FragmentsActivities等。适配器只能向上层发送点击事件。它应该有接口ItemClickListener 有这么多事件,因为许多事件适配器的视图可以产生。这个解决方案写得更早:stackoverflow.com/a/40563598/2914140.
    【解决方案3】:

    您应该将 RecyclerView LayoutManager 设置为 Gridlayout 模式。当您想设置RecyclerView LayoutManager 时,只需更改您的代码:

    recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), numberOfColumns));
    

    【讨论】:

      【解决方案4】:

      这是一种仅来自 XML 的简单方法

      spanCount 表示列数

      layoutManager 用于使其成为网格或线性(垂直或水平)

      <androidx.recyclerview.widget.RecyclerView
              android:id="@+id/personListRecyclerView"
              android:layout_width="0dp"
              android:layout_height="0dp"
              app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
              app:spanCount="2"
              app:layout_constraintBottom_toBottomOf="parent"
              app:layout_constraintEnd_toEndOf="parent"
              app:layout_constraintHorizontal_bias="0.5"
              app:layout_constraintStart_toStartOf="parent"
              app:layout_constraintTop_toTopOf="parent" />
      

      【讨论】:

        【解决方案5】:

        RecyclerView初始化中设置

        recyclerView.setLayoutManager(new GridLayoutManager(this, 4));
        

        【讨论】:

        • 它与其他答案有何不同?
        【解决方案6】:

        在您分配回收站视图的 MainActivity 中,只需使用此代码即可。

        recyclerView = findViewById(R.id.recycler_view);
            recyclerView.setHasFixedSize(true);
            //recyclerView.setLayoutManager(new LinearLayoutManager(this));
            recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
        

        【讨论】:

          【解决方案7】:

          如果你想在 xml 文件中的 reyclerview 中设置网格布局,那么你可以将这两个放在 recyclerview xml 中。

          app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
          app:spanCount=numberOfItemsInSignleRow
          

          如果你想通过 java 代码设置网格布局,你可以这样写。

          recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), numberOfItemsInSignleRow));
          

          【讨论】:

            【解决方案8】:
                There are 2 ways to achieve this 
                
                - In Xml
                 <androidx.recyclerview.widget.RecyclerView
                                        android:id="@+id/list_amenities"
                                        android:layout_width="0dp"
                                        android:layout_height="wrap_content"
                                        android:layout_marginTop="@dimen/_8sdp"
                                        android:nestedScrollingEnabled="false"                 
             app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
                                        app:spanCount="2"
            app:layout_constraintEnd_toEndOf="@+id/text_parking_lot_amenities"                       app:layout_constraintStart_toStartOf="@+id/text_parking_lot_amenities"                  app:layout_constraintTop_toBottomOf="@id/text_parking_lot_amenities" />
            

            跨度计数用于网格列
            - 在活动中

             listAmenities.layoutManager = GridLayoutManager(this, TWO)
             here TWO indicates number of grid columns
            

            【讨论】:

              猜你喜欢
              • 2017-03-27
              • 2010-11-02
              • 2020-02-07
              • 1970-01-01
              • 2023-03-15
              • 2016-02-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多