RecyclerView有标题栏的分类列表 自定义列数(不同行设置不同个子项item)

上一个的实验室Issue前几天才完成,两个项目都实现了老师要求,算上中途多次放下去做其他issue,这个issue做了差不多有四个月了吧。还好不是改bug,不然四个月时间足够被批评n次了。趁着现在还有印象,把这个issue里最难搞的问题总结一下,之前做的过程也总结了一些遇到的问题,比如后台多个定时器同事运行的问题,settings界面的注意事项等都总结了,这次总结一下花费最多时间去想的问题,中途还经过多次推倒重来,也不是说这个功能多难实现,主要是在几年前的项目上添加新功能,有些吃力,毕竟好多方法都被调用过,不能随意改变,尤其是数据封装好的类型很难去改变,想要找到一个好的方法挺难的,只能找一些折中的方法。这篇博文讲解的是我自己想的一种方法,可能不是最好的,但是适合我的项目,如果有比较好的方法,欢迎一起讨论。


有时候需要对一些数据进行分类显示,还要显示他们的分类标题,普通的GridView是挺难实现的,因为GridView不支持不同行自定义列数,例如我想标题占满一行,其他子项每两个占一行。GridView也可以实现,需要对GridView的方法做大量地重写override,重绘item等等,对一些像我这种菜鸟级别的人来说,门槛太高。后来发现可以使用RecyclerView实现这种功能,RecyclerView支持自定义不同列数。接下来介绍一下如何使用。

  1. 先看一下做的项目的效果图
    RecyclerView有标题栏的分类列表 自定义列数(不同行设置不同个子项item)_第1张图片

解释都写在代码里,直接看代码吧:

  • 先分别新建一个title的layout文件和一个item的layout文件
    recyclerview_title.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:text="标题"/>
LinearLayout>

recyclerview_item.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/image"
    android:scaleType="fitXY"
    android:alpha="0.7"
    android:src="@drawable/ic_launcher_background"/>

<TextView
    android:id="@+id/item"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_alignParentTop="true"
    android:layout_marginTop="40dp"
    android:gravity="center"
    android:text="这是一个item"
    android:textColor="#ffffff"
    android:textSize="20sp" />
RelativeLayout>
  • 主界面的layout文件代码:
    activity_recycler_view_category_style.xml
<ScrollView 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="com.example.mrc.csdndemo.RecyclerViewCategory.RecyclerViewCategoryStyle">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:numColumns="auto_fit"
            android:stretchMode="columnWidth"
            android:layout_width="fill_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:horizontalSpacing="8dp"
            android:verticalSpacing="8dp"/>/>
    LinearLayout>
ScrollView>
  • 新建一个RecyclerView的适配器,代码如下:
    RecyclerViewAdapter.java
package com.example.mrc.csdndemo.RecyclerViewCategory;

import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
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.TextView;
import com.example.mrc.csdndemo.R;
import java.util.List;
import java.util.Map;

/**
 * Created by Mr.C on 2018/3/17.
 */

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>{
    private Context mContext;
    private LayoutInflater mInflater;
    private static final int VIEW_TYPE_TITLE= 0;
    private static final int VIEW_TYPE_ITEM = 1;
    int IS_TITLE_OR_NOT =1;
    int MESSAGE = 2;
    int ColumnNum;
    List> mData;


    public RecyclerViewAdapter(Context context , List> mData , int ColumnNum) {
        this.mContext=context;
        this.ColumnNum=ColumnNum;
        this.mData= mData;
    }

    @Override
    public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ViewHolder  vh = null;
        mInflater = LayoutInflater.from(mContext);
        //判断viewtype类型返回不同Viewholder
        switch (viewType) {
            case VIEW_TYPE_TITLE:
                vh = new HolderOne(mInflater.inflate(R.layout.recyclerview_title, parent, false));
                break;
            case VIEW_TYPE_ITEM:
                vh = new HolderTwo(mInflater.inflate(R.layout.recyclerview_item, parent,false));
                break;
        }
        return vh;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        if("true".equals(mData.get(position).get(IS_TITLE_OR_NOT))){
            holder.mTitle.setText(mData.get(position).get(MESSAGE));
        }else {
            holder.mItem.setText(mData.get(position).get(MESSAGE));
        }

    }

    //判断RecyclerView的子项样式,返回一个int值表示
    @Override
    public int getItemViewType(int position) {
        if ("true".equals(mData.get(position).get(IS_TITLE_OR_NOT))) {
            return VIEW_TYPE_TITLE;
        }
        return VIEW_TYPE_ITEM;
    }

    //判断是否是title,如果是,title占满一行的所有子项,则是ColumnNum个,如果是item,占满一个子项
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        //如果是title就占据2个单元格(重点)
        GridLayoutManager manager = (GridLayoutManager) recyclerView.getLayoutManager();
        manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                if("false".equals(mData.get(position).get(IS_TITLE_OR_NOT))){
                    return 1;
                }else {
                    return ColumnNum;
                }
            }
        });
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position , List payloads) {
        if(payloads.isEmpty()){
            onBindViewHolder(holder,position);
        } else {
            onBindViewHolder(holder,position);
        }
    }

    //对于不同布局的子项,需要对它进行初始化
    @Override
    public int getItemCount() {
        return mData.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public TextView mTitle;
        public TextView mItem;
        public ImageView mImageView;
        public ViewHolder(View itemView) {
            super(itemView);
        }
    }
    public class HolderOne extends ViewHolder {

        public HolderOne(View viewHolder) {
            super(viewHolder);
            mTitle= (TextView) viewHolder.findViewById(R.id.title);
        }
    }

    public class HolderTwo extends ViewHolder{

        public HolderTwo(final View viewHolder) {
            super(viewHolder);
            mItem =(TextView)viewHolder.findViewById(R.id.item);
            mImageView =(ImageView) viewHolder.findViewById(R.id.image);
        }
    }
}
 
  
  • 最后就是主界面的Java文件
    RecyclerViewCategoryStyle.java
package com.example.mrc.csdndemo.RecyclerViewCategory;

import android.graphics.Rect;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;

import com.example.mrc.csdndemo.R;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class RecyclerViewCategoryStyle extends AppCompatActivity {
    RecyclerView mRecyclerView ;
    LinearLayoutManager mLayoutManager;
    RecyclerViewAdapter mRecyclerViewAdapter;

    int IS_TITLE_OR_NOT =1;
    int MESSAGE = 2;

    List> mData =new ArrayList<>();
    Map map = new HashMap();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_view_category_style);

        findView();
        init();
        mRecyclerViewAdapter = new RecyclerViewAdapter(this, mData, 2);
        mRecyclerView.setAdapter(mRecyclerViewAdapter);
    }

    void findView(){
        mRecyclerView =(RecyclerView)findViewById(R.id.recyclerView);
        //2表示列数为2,LinearLayoutManager.VERTICAL表示竖直布局
        mLayoutManager = new GridLayoutManager(this, 2, LinearLayoutManager.VERTICAL, false);
        mRecyclerView.addItemDecoration(new SpaceItemDecoration(12));//item之间的间距
        mRecyclerView.setLayoutManager(mLayoutManager);
    }


    void init(){
        //对item的数据进行初始化
        for(int i=0;i<15 ;i++){
            map = new HashMap();
            map.put(IS_TITLE_OR_NOT , "false");
            map.put(MESSAGE , "item "+(i+1));
            mData.add(map);
        }

        //对分类标题进行初始化
        map = new HashMap();
        map.put(IS_TITLE_OR_NOT , "true");
        map.put(MESSAGE , "1-3的分类标题");
        mData.add(0,map);

       map = new HashMap();
        map.put(IS_TITLE_OR_NOT , "true");
        map.put(MESSAGE , "4-7的分类标题");
        mData.add( 4,map);

        map = new HashMap();
        map.put(IS_TITLE_OR_NOT , "true");
        map.put(MESSAGE , "8-15的分类标题");
        mData.add(9,map);
        for (int i=0;i"Title",mData.get(i).get(IS_TITLE_OR_NOT));
            Log.d("Title_message",mData.get(i).get(MESSAGE));
        }
    }


    //设置recyclerView中item的上下左右间距
    public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
        private int space;

        public SpaceItemDecoration(int space) {
            this.space = space;
        }

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            //分别设置item的间距
            if (parent.getChildViewHolder(view).getItemViewType() == 0) {
                outRect.bottom = 0;
                outRect.top = space / 2;
            } else {
                outRect.bottom = space;
                outRect.top = space;
            }
            outRect.right = space;
            outRect.left = space;

        }
    }
}

这是我写的Demo的效果图:
RecyclerView有标题栏的分类列表 自定义列数(不同行设置不同个子项item)_第2张图片

代码已经打包放在里面,看不懂的伙伴可以去下载下来研究研究:
RecyclerView有标题栏的分类列表 自定义列数(不同行设置不同个子项item)

你可能感兴趣的:(android)