Android中RecyclerView点击item展开二级列表的简单实现(代码详细讲解)

Android中RecyclerView可展开二级列表及非展开二级列表(代码详细讲解)

一、大体介绍

  最近在学安卓的基础知识recylcerview,然后去网上搜了很多代码,发现写的比较复杂,于是自己在leader的指导下写了一个简单的代码,并且有完整的代码实现以及详细代码讲解。想要学习的小伙伴可不要错过了!所有的完整代码都标注了!
  最开始学习此view的时候是由浅入深的,因此如果一开始就上来做可展开二级列表会有点难度,因此我们可以从最简单的非展开二级列表来完成,然后循序渐进,做出来可折叠的二级列表。
  首先看一下主界面(对应的是activity_main.xml和MainActivity),也就是如下图所示:

  非折叠菜单的图如下所示,也就是说一级标题和二级标题并没有区分,只是布局有所不同,既一级标题不能展开二级标题:

  折叠版本的如下所示,一级标题可以进行展开和关闭(动图不会做,请见谅):

  同时,可以点击界面:如果点击一级标题则会出现toast响应事件:

  如果点击二级标题,则会直接跳转到新的界面:

  整体文件如下所示:

二、XML界面介绍

1.activity_main.xml

  这个主要是展现主界面的,整体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <Button
        android:id="@+id/button1"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="60dp"
        android:text="非折叠菜单" />

    <Button
        android:id="@+id/button2"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="60dp"
        android:text="折叠菜单"/>
</LinearLayout>

2. nofold_layout.xml

  这个界面主要是用来存放一个recyclerview布局的,对应的是非折叠界面,和fold_layout.xml界面一样:

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

    <android.support.v7.widget.RecyclerView
        android:id="@+id/nofold_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

3. fold_layout.xml

  对应的是折叠界面:

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

    <android.support.v7.widget.RecyclerView
        android:id="@+id/fold_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

4. parent_caption.xml

  一级标题和二级标题的布局格式是不一样的,因此我采取了两个xml界面来进行布局管理,parent_caption.xml管理的是一级标题,用的都是LinearLayout线性布局:

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

    <TextView
        android:id="@+id/parent_textview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="15dp"
        android:textSize="16sp"
        android:textStyle="bold" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:background="@color/gray" />

</LinearLayout>

5. child_caption.xml

   是二级标题的布局格式:

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

    <TextView
        android:id="@+id/child_textview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="30dp"
        android:layout_marginLeft="30dp"
        android:padding="20dp"
        android:textSize="16sp"
        android:textStyle="bold" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:background="@color/gray" />

</LinearLayout>

三、MapBean介绍

  我创建了一个MapBean类来封装我需要的变量,参数和方法,整体代码如下所示:

package com.shuting.myapplication.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class MapBean implements Serializable {

    public static final int TYPE_PARENT=0;//父类标题,即一级标题
    public static final int TYPE_CHILD=1;//子类,即二级标题

    private int viewType;   //判断标题类型是TYPE_PARENT还是TYPE_CHILD来对应不同的布局
    private String caption; //标题的内容

	//表示获得的标题内容以及标题类型(父标题还是子标题)
    public MapBean(String caption,int viewType){
        this.caption=caption;
        this.viewType=viewType;
    }
	
    public int getViewType(){return viewType;}//获得对应的标题类型

    public String getCaption(){ //获得标题内容
        return caption;
    }

    //折叠展开列表
    private List<MapBean> childList;//定义一个装载多个子类的列表
    private boolean expand=false; //是否展开子项

    public void setChildList(List<MapBean> childList){ //构建子项列表
        this.childList=childList;
    }
    public List<MapBean> getChildList(){//获得存放子标题的列表
        return childList;
    }
    public boolean isExpand(){//判断现在的状态是扩展还是折叠
        return expand;
    }
    public void setExpand(boolean expand){//建立父标题的状态
        this.expand=expand;
    }

}

  这个MapBean里面关键点其实在于以下几个部分:
  1)如何来区分是父标题还是子标题,我们加入了一个viewType,如果是TYPE_PARENT,则是父标题,TYPE_CHILD则是子标题;
  2)我们想让父标题包含多个子标题,那么在父标题中我们定义一个List < < <mapBean > > >childList,目的是用列表存放多个子标题实例。
  3)当父标题需要折叠或者展开的时候需要区分其状态,因此我们定义了一个boolean expand,用来判断父标题是什么状态,如果是展开则进行折叠,如果折叠则进行展开。
  4)当我们需要传输列表中的数据的时候,需要让mapBean继承Serializable接口,这样在后面intent传值的时候才可以使用。

四、数据初始化方法介绍

  我的想法是让两个界面都共享同样的数据,这样修改比较方便,因此我们需要在开始就进行数据的初始化:

1. MainActivity

    private void initMaps() {
        String[] parent = {"动物", "植物"};
        String[][] child= {{"熊猫", "大象", "老虎"},
                           {"百合", "向日葵", "樱花"}};
        for (int i = 0; i < parent.length; i++) {
            MapBean parentBean = new MapBean(parent[i], MapBean.TYPE_PARENT);
            List<MapBean> childList = new ArrayList<>();//保存二级标题
            for (int j = 0; j < child[i].length; j++) {
                MapBean childBean = new MapBean(child[i][j], MapBean.TYPE_CHILD);
                childList.add(childBean);
            }
            parentBean.setChildList(childList);
            mapBeanList.add(parentBean);
        }

    }

  首先我们用一个一维字符串数组parent来保存父标题,用一个二维字符串数组child来保存子标题,然后为每一个父标题创建一个MapBean实例,然后再为每一个MapBean创建属于他们的子标题列表childList,里面则存放着所对应的子标题实例,这样就可以保证拿到一个父标题,我们就知道他的子标题是什么了。
  整体代码如下所示:

public class MainActivity extends AppCompatActivity {
    private Button button1;
    private Button button2;
    private List<MapBean> mapBeanList = new ArrayList<>();//初始化保存标题,然后通过intent传输到各个activity中

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button1 = findViewById(R.id.button1);
        button2 = findViewById(R.id.button2);
        initMaps();

        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, NoFoldActivity.class);
                onClicks(intent);
            }
        });

        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, FoldActivity.class);
                onClicks(intent);
            }
        });
    }

    public void onClicks(Intent intent) {
        Bundle bundle = new Bundle();
        bundle.putSerializable("mapBeanList", (Serializable) mapBeanList);//把list强转成Serializable类型
        intent.putExtras(bundle);
        startActivity(intent);
    }

    private void initMaps() {
        String[] parent = {"动物", "植物"};
        String[][] child= {{"熊猫", "大象", "老虎"},
                           {"百合", "向日葵", "樱花"}};
        for (int i = 0; i < parent.length; i++) {
            MapBean parentBean = new MapBean(parent[i], MapBean.TYPE_PARENT);
            List<MapBean> childList = new ArrayList<>();//保存二级标题
            for (int j = 0; j < child[i].length; j++) {
                MapBean childBean = new MapBean(child[i][j], MapBean.TYPE_CHILD);
                childList.add(childBean);
            }
            parentBean.setChildList(childList);
            mapBeanList.add(parentBean);
        }

    }

}

五、Adapter介绍

1. NoFoldAdapter

  这个主要是为不能折叠的界面做的一个适配器,代码有点长,我们对每一部分进行一个仔细的分析:

public class NoFoldAdapter extends RecyclerView.Adapter {
    private List<MapBean> mapBeanList=new ArrayList<>();//建立一个存放标题的列表
    private LayoutInflater inflater;
    private Context context;//上下文
    
  static class ParentViewHolder extends RecyclerView.ViewHolder {
        TextView parentTextview;

        public ParentViewHolder(View view) {
            super(view);//view参数就是RecyclerView子项最外层布局,也就是parent_caption
            parentTextview = view.findViewById(R.id.parent_textview);
            //通过findViewById()方法获取到布局中的实例
        }
    }

    static class ChildViewHolder extends RecyclerView.ViewHolder {
        TextView childTextview;

        public ChildViewHolder(View view) {
            super(view);
            childTextview = view.findViewById(R.id.child_textview);
        }
    }

  上述是根据我们有父标题和子标题两种不同的布局,因此我们在NoFoldAdapter中定义了两个静态类,其实就是为了在引入view之后可以获取到不同view对应的布局实例。

    public NoFoldAdapter(List<MapBean> mBeanList) {
        int len=mBeanList.size();
        //this.mapBeanList = mBeanList;
        for(int i=0;i<len;i++){
            MapBean mapBean=mBeanList.get(i);
            mapBeanList.add(mapBean);
            List<MapBean> childList=mapBean.getChildList();//获取子项标题
            for(int j=0;j<childList.size();j++){
                mapBeanList.add(childList.get(j));
            }
        }

    }

  注意这个地方,因为在数据初始化的时候我们把子标题都存到父标题的childList列表中了,此时非折叠的布局不需要父标题和子标题之间的相关性,仅仅需要将他们以不同的布局展示出来,因此这个时候我们依次将父标题和父标题childList列表中的所有子标题都按照顺序取出并放到mapBeanList中,这样就可以按照父标题1,子标题1-1,子标题1-2,父标题2,子标题2-1,子标题2-2的方式在界面上显示出来了。

    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if(context==null){
            context=parent.getContext();
        }
        if (inflater == null) {//如果没有这一行判断则会出错
            inflater = LayoutInflater.from(context);
        }
        View view;
        switch (viewType) {
            case MapBean.TYPE_PARENT:
                //view=LayoutInflater.from(parent.getContect()).inflate() 则会出错
                view = inflater.inflate(R.layout.parent_caption, parent, false);//要动态加载的布局
                return new ParentViewHolder(view);
            case MapBean.TYPE_CHILD:
                view = inflater.inflate(R.layout.child_caption, parent, false);//要动态加载的布局
                return new ChildViewHolder(view);
        }
        return null;
    }

  这个是需要重写的函数onCreateViewHolder方法,目的是动态加载布局文件,然后生成不同布局对应的holder实例,我们可以根据传来的viewtype进行判断是父标题还是子标题然后返回对应item布局的ViewHolder实例。代码里面的view其实是一个泛指,是父标题和子标题的父类,我们可以先动态加载出view布局,然后对父标题布局/子标题布局进行一个实例化。
  通俗的来讲,就是我们为不同的标题类型创建了不同的布局,并且需要对布局中的每一个例如textView,button等控件进行实例化。

    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        MapBean mapBean;
        //通过position参数得到当前项的mapBean实例
        if (holder instanceof ParentViewHolder) {
            mapBean = mapBeanList.get(position);
            ((ParentViewHolder) holder).parentTextview.setText(mapBean.getCaption());
            ((ParentViewHolder) holder).parentTextview.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(v.getContext(), "you clicked parent " + mapBean.getCaption(),
                            Toast.LENGTH_SHORT).show();
                }
            });
        } else if (holder instanceof ChildViewHolder) {
            mapBean = mapBeanList.get(position);
            ((ChildViewHolder) holder).childTextview.setText(mapBean.getCaption());
            ((ChildViewHolder) holder).childTextview.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent=new Intent();
                    intent.putExtra("caption",mapBean.getCaption());
                    intent.setClass(context, JumpAvtivity.class);
                    context.startActivity(intent);
                }
            });
        }
    }

  用于对RecyclerView子项的数据进行赋值,会在每个子项被滚动到屏幕内的时候执行,同时如果得到的是父标题,那我们则采用一个toast来弹出当前点击的位置是什么内容,如果得到的是子标题实例,则采用intent传值的方法跳转到新的页面当中去。

  整体代码如下所示:

public class NoFoldAdapter extends RecyclerView.Adapter {
    private List<MapBean> mapBeanList=new ArrayList<>();
    private LayoutInflater inflater;
    private Context context;

    static class ParentViewHolder extends RecyclerView.ViewHolder {
        TextView parentTextview;

        public ParentViewHolder(View view) {
            super(view);//view参数就是RecyclerView子项最外层布局,也就是parent_caption
            parentTextview = view.findViewById(R.id.parent_textview);
            //通过findViewById()方法获取到布局中的实例
        }
    }

    static class ChildViewHolder extends RecyclerView.ViewHolder {
        TextView childTextview;

        public ChildViewHolder(View view) {
            super(view);
            childTextview = view.findViewById(R.id.child_textview);
        }
    }

    //把要展示的数据源传进来,并赋值给一个全局变量mapBeanList,后续的操作都将在这个数据源的基础上进行
    //由于现在是一个一级标题套着多个小标题,则需要把数据按顺序取出来
    public NoFoldAdapter(List<MapBean> mBeanList) {
        int len=mBeanList.size();
        //this.mapBeanList = mBeanList;
        for(int i=0;i<len;i++){
            MapBean mapBean=mBeanList.get(i);
            mapBeanList.add(mapBean);
            List<MapBean> childList=mapBean.getChildList();//获取子项标题
            for(int j=0;j<childList.size();j++){
                mapBeanList.add(childList.get(j));
            }
        }

    }

    public int getItemViewType(int position) {
        if (mapBeanList.size() > 0) {
            return mapBeanList.get(position).getViewType();//返回当前位置对应的viewType
        }
        return super.getItemViewType(position);
    }

    //动态加载布局文件,然后生成不同布局对应的holder实例,需要进行判断当前列表项的类型,来初始化不同的Holder
    //根据onCreateViewHolder方法传来的viewtype进行判断然后返回对应item布局的ViewHolder实例
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if(context==null){
            context=parent.getContext();
        }
        if (inflater == null) {//如果没有这一行判断则会出错
            inflater = LayoutInflater.from(context);
        }
        View view;
        switch (viewType) {
            case MapBean.TYPE_PARENT:
                //view=LayoutInflater.from(parent.getContect()).inflate() 则会出错
                view = inflater.inflate(R.layout.parent_caption, parent, false);//要动态加载的布局
                return new ParentViewHolder(view);
            case MapBean.TYPE_CHILD:
                view = inflater.inflate(R.layout.child_caption, parent, false);//要动态加载的布局
                return new ChildViewHolder(view);
        }
        return null;
    }

    //用于对RecyclerView子项的数据进行赋值,会在每个子项被滚动到屏幕内的时候执行
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        MapBean mapBean;
        //通过position参数得到当前项的mapBean实例
        if (holder instanceof ParentViewHolder) {
            mapBean = mapBeanList.get(position);
            ((ParentViewHolder) holder).parentTextview.setText(mapBean.getCaption());
            ((ParentViewHolder) holder).parentTextview.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(v.getContext(), "you clicked parent " + mapBean.getCaption(),
                            Toast.LENGTH_SHORT).show();
                }
            });
        } else if (holder instanceof ChildViewHolder) {
            mapBean = mapBeanList.get(position);
            ((ChildViewHolder) holder).childTextview.setText(mapBean.getCaption());
            ((ChildViewHolder) holder).childTextview.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent=new Intent();
                    intent.putExtra("caption",mapBean.getCaption());
                    intent.setClass(context, JumpAvtivity.class);
                    context.startActivity(intent);
                }
            });
        }
    }

    public int getItemCount() {
        return mapBeanList.size();
    }
}

2. FoldAdapter

  和NoFoldAdapter很类似,但是不同的点我需要列出来进行分析:

 public FoldAdapter(List<MapBean> mapBeanList) {
        this.mapBeanList = mapBeanList;
    }

  和之前的把要展示的数据源传进来,并赋值给一个全局变量mapBeanList不同,我们需要父标题和子标题之间的关联,因此我们直接将mapBeanList传进来。

  主要看onBindViewHolder方法中父标题是如何进行折叠与展开的:

        if (holder instanceof ParentViewHolder) {
            //如果是父类型,则要去找其对应的子类列表里面的个数并进行展示
            mapBean = mapBeanList.get(position);
            ((ParentViewHolder) holder).parentTextview.setText(mapBean.getCaption());
            ((ParentViewHolder) holder).parentTextview.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = holder.getAdapterPosition();//找到对应的位置
                    MapBean mapBean = mapBeanList.get(position);//根据位置获取到实例
                    List<MapBean> childList = mapBean.getChildList();//获取实例对应的子项
                    if (childList.size() == 0) {
                        return;
                    }
                    if (mapBean.isExpand()) {//如果是展开的则删除子项.从position+1开始删除childList.size()个
                        for (int i = 1; i <= childList.size(); i++) {
                            mapBeanList.remove(position + 1);
                            notifyItemRemoved(position + 1);//更新状态
                        }
                        mapBean.setExpand(false);//将其设为已经折叠
                    } else {
                        //是折叠状态则进行添加,由于position是不变的,然后需要在下方一直插入,则需要倒着插入
                        for (int i = childList.size() - 1; i >= 0; i--) {
                            mapBeanList.add(position + 1, childList.get(i));
                            notifyItemInserted(position + 1);
                        }
                        mapBean.setExpand(true); //将其设置为已展开
                    }

                }
            });
        } 

  我们首先可以根据holder实例来判断对应的是父标题还是子标题,如果是父标题,则根据position来获取到当前得到的父标题实例,如果当前父标题是展开状态的话,那么需要删除子项,但是如何获得子项的个数呢?这个时候我们需要需要根据下面一行代码来获得父标题对应的子标题的列表,由于position的位置是一直固定的,我们必须以它为标准,也就是说,当删除子标题的时候,我们只能对position+1的位置,也就是父标题下面一个位置进行删除,然后下面的子标题补上来,因此对子标题列表进行遍历,从mapBeanList中不断删除position+1位置的子标题,然后不断进行更新,当全部删除完毕后,需要将父标题的状态进行更新,

List<MapBean> childList = mapBean.getChildList()

  如果父标题是折叠的,那么我们需要进行展开,与上面同理,我们需要把子标题依次加入到mapBeanList中来在界面中显示,由于我们每一次都是添加在postion+1的位置,因此我们需要倒着将子标题添加进去,这样就相当于后加入的子标题把之前加入的子标题挤到下面去了,然后在全部添加完毕后,则更新父标题状态.

整体代码如下所示:

public class FoldAdapter extends RecyclerView.Adapter {

    private List<MapBean> mapBeanList;
    private LayoutInflater inflater;
    private Context context;

    static class ParentViewHolder extends RecyclerView.ViewHolder {
        TextView parentTextview;

        public ParentViewHolder(View view) {
            super(view);//view参数就是RecyclerView子项最外层布局,也就是parent_caption
            parentTextview = view.findViewById(R.id.parent_textview);
            //通过findViewById()方法获取到布局中的实例
        }
    }

    static class ChildViewHolder extends RecyclerView.ViewHolder {
        TextView childTextview;

        public ChildViewHolder(View view) {
            super(view);
            childTextview = view.findViewById(R.id.child_textview);
        }
    }

    //把要展示的数据源传进来,并赋值给一个全局变量mapBeanList,后续的操作都将在这个数据源的基础上进行
    public FoldAdapter(List<MapBean> mapBeanList) {
        this.mapBeanList = mapBeanList;
    }

    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (context == null) {
            context = parent.getContext();
        }
        if (inflater == null) {//如果没有这一行判断则会出错
            inflater = LayoutInflater.from(context);
        }

        View view;
        switch (viewType) {
            case MapBean.TYPE_PARENT:
                //view=LayoutInflater.from(parent.getContect()).inflate() 则会出错
                view = inflater.inflate(R.layout.parent_caption, parent, false);//要动态加载的布局
                return new FoldAdapter.ParentViewHolder(view);
            case MapBean.TYPE_CHILD:
                view = inflater.inflate(R.layout.child_caption, parent, false);//要动态加载的布局
                return new FoldAdapter.ChildViewHolder(view);
        }
        return null;
    }

    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        MapBean mapBean;
        if (holder instanceof ParentViewHolder) {
            //如果是父类型,则要去找其对应的子类列表里面的个数并进行展示
            mapBean = mapBeanList.get(position);
            ((ParentViewHolder) holder).parentTextview.setText(mapBean.getCaption());
            ((ParentViewHolder) holder).parentTextview.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = holder.getAdapterPosition();//找到对应的位置
                    MapBean mapBean = mapBeanList.get(position);//根据位置获取到实例
                    List<MapBean> childList = mapBean.getChildList();//获取实例对应的子项
                    if (childList.size() == 0) {
                        return;
                    }
                    if (mapBean.isExpand()) {//如果是展开的则删除子项.从position+1开始删除childList.size()个
                        for (int i = 1; i <= childList.size(); i++) {
                            mapBeanList.remove(position + 1);
                            notifyItemRemoved(position + 1);//更新状态
                        }
                        mapBean.setExpand(false);//将其设为已经折叠
                    } else {
                        //是折叠状态则进行添加,由于position是不变的,然后需要在下方一直插入,则需要倒着插入
                        for (int i = childList.size() - 1; i >= 0; i--) {
                            mapBeanList.add(position + 1, childList.get(i));
                            notifyItemInserted(position + 1);
                        }
                        mapBean.setExpand(true); //将其设置为已展开
                    }

                }
            });
        } else if (holder instanceof ChildViewHolder) {
            mapBean = mapBeanList.get(position);
            ((ChildViewHolder) holder).childTextview.setText(mapBean.getCaption());
            ((ChildViewHolder) holder).childTextview.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent=new Intent();
                    intent.putExtra("caption",mapBean.getCaption());
                    intent.setClass(context, JumpAvtivity.class);
                    context.startActivity(intent);
                }
            });
        }
    }

    public int getItemCount() {
        return mapBeanList.size();
    }

    public int getItemViewType(int position) {
        return mapBeanList.get(position).getViewType();
    }
}

五、Activity介绍

1. FoldActivity

  整体代码如下所示,就是获取到mapBeanList然后进行线性布局的管理以及适配器的管理:

public class FoldActivity extends AppCompatActivity {
    private List<MapBean> mapBeanList=new ArrayList<>();
    private RecyclerView recyclerView;
    private FoldAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fold_layout);
        Intent intent=getIntent();
        Bundle bundle=intent.getExtras();
        mapBeanList=(List<MapBean>)bundle.getSerializable("mapBeanList");
        if(mapBeanList.size()==0){
            Toast.makeText(this,"没有对应数据",Toast.LENGTH_SHORT).show();
        }
        recyclerView=findViewById(R.id.fold_recyclerview);

        LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);
        adapter=new FoldAdapter(mapBeanList);
        recyclerView.setAdapter(adapter);
    }
}

2. NoFoldActivity

  整体代码如下所示:

public class NoFoldActivity extends AppCompatActivity {
    private List<MapBean> mapBeanList=new ArrayList<>();
    private RecyclerView recyclerView;
    private NoFoldAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.nofold_layout);
        Intent intent=getIntent();
        Bundle bundle=intent.getExtras();
        mapBeanList=(List<MapBean>)bundle.getSerializable("mapBeanList");

        if(mapBeanList.size()==0){//判断是否为空
            Toast.makeText(this, "没有数据!",
                    Toast.LENGTH_SHORT).show();
        }
        recyclerView=findViewById(R.id.nofold_recyclerview);
        LinearLayoutManager layoutManager=new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        adapter=new NoFoldAdapter(mapBeanList);
        recyclerView.setAdapter(adapter);
    }

}

  额外补充一点,注意,我们的mapBeanList是从MainActivity类中传递过来的,方法如下:

 		Intent intent = new Intent(MainActivity.this, FoldActivity.class);
        Bundle bundle = new Bundle();
        bundle.putSerializable("mapBeanList", (Serializable) mapBeanList);//把list强转成Serializable类型
        intent.putExtras(bundle);
        startActivity(intent);

  然后获得的方法是:

   Intent intent=getIntent();
        Bundle bundle=intent.getExtras();
        mapBeanList=(List<MapBean>)bundle.getSerializable("mapBeanList");

3. JumpActivity

public class JumpAvtivity extends AppCompatActivity {
    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.jump_layout);
        textView=findViewById(R.id.jump_textview);
        Intent intent=getIntent();
        String caption=intent.getStringExtra("caption");
        textView.setText(caption);
    }
}

  大体就是这么多啦,要是有什么疑问可以问我,也可以对这片文章的不懂之处进行提问,我可以进行一个更加详细的介绍和优化!

  • 8
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
实现RecyclerView点击item后背景平移到选item,可以通过自定义RecyclerViewItemDecoration来实现。以下是实现的步骤: 1. 在res/drawable文件夹下创建一个selector文件,用来设置RecyclerView item的背景色变化。例如,创建一个名为background_item.xml的文件,代码如下: ```xml <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"> <shape android:shape="rectangle"> <solid android:color="@color/colorPrimaryDark" /> </shape> </item> <item android:state_selected="true"> <shape android:shape="rectangle"> <solid android:color="@color/colorAccent" /> </shape> </item> <item> <shape android:shape="rectangle"> <solid android:color="@color/colorPrimary" /> </shape> </item> </selector> ``` 这里定义了三个状态,分别是按下状态、选状态和普通状态,分别设置了不同的背景颜色。 2. 在RecyclerView的Adapter,设置ItemView的背景为上述selector文件,例如: ```kotlin override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false) view.setBackgroundResource(R.drawable.background_item) return ViewHolder(view) } ``` 3. 在RecyclerViewItemDecoration,定义一个变量mSelectedPosition,用于记录当前选item位置。在item点击事件,更新mSelectedPosition变量的值,并调用RecyclerView的invalidateItemDecorations()方法刷新ItemDecoration,例如: ```kotlin class CustomItemDecoration : RecyclerView.ItemDecoration() { private val mPaint = Paint() private val mOffset = 20 // 偏移量 private val mTopLeftRectF = RectF() private val mBottomRightRectF = RectF() private var mSelectedPosition = RecyclerView.NO_POSITION // 当前选item位置 init { mPaint.color = Color.WHITE mPaint.isAntiAlias = true } override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { super.onDraw(c, parent, state) val childCount = parent.childCount for (i in 0 until childCount) { val child = parent.getChildAt(i) val params = child.layoutParams as RecyclerView.LayoutParams // 计算矩形区域 val left = child.left - params.leftMargin - mOffset val top = child.top - params.topMargin - mOffset val right = child.right + params.rightMargin + mOffset val bottom = child.bottom + params.bottomMargin + mOffset mTopLeftRectF.set(left.toFloat(), top.toFloat(), child.left.toFloat(), child.top.toFloat()) mBottomRightRectF.set(child.right.toFloat(), child.bottom.toFloat(), right.toFloat(), bottom.toFloat()) // 绘制背景 if (parent.getChildAdapterPosition(child) == mSelectedPosition) { c.drawRoundRect(mTopLeftRectF, 10f, 10f, mPaint) c.drawRoundRect(mBottomRightRectF, 10f, 10f, mPaint) } } } fun setSelectedPosition(position: Int) { if (mSelectedPosition != position) { mSelectedPosition = position recyclerView?.invalidateItemDecorations() } } } ``` 这里的setSelectedPosition方法用于更新mSelectedPosition变量的值,并调用RecyclerView的invalidateItemDecorations()方法刷新ItemDecoration。 4. 在RecyclerViewitem点击事件,调用上述ItemDecoration的setSelectedPosition方法更新选item位置,例如: ```kotlin recyclerView.addOnItemTouchListener(object : RecyclerView.OnItemTouchListener { override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean { when (e.action) { MotionEvent.ACTION_UP -> { val child = rv.findChildViewUnder(e.x, e.y) if (child != null) { val position = rv.getChildAdapterPosition(child) customItemDecoration.setSelectedPosition(position) // 处理item点击事件 onItemClick(position) return true } } } return false } override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {} override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {} }) ``` 这里的onItemClick方法用于处理item点击事件,具体实现可根据实际需求进行编写。 这样,点击RecyclerViewitem时就能实现背景平移效果并且选item背景颜色不会消失了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值