RecyclerView多布局的简单
RecyclerView 是在Android5.0之后推出的,是一个比ListView更加灵活更加高效的适配器类型控件。但是RecyclerView不同于其他类型的适配器,它还需要一个LayoutManager进行页面控制展示。RecyclerView提供了三种布局管理器:
1、LinearLayoutManager:线性布局管理器,支持水平和垂直效果。
2、GridLayoutManager:网格布局管理器,支持水平和垂直效果。
3、StaggeredGridLayoutManager:分布型管理器,瀑布流效果
RecyclerView的使用:
1、引入RecyclerView依赖包,V7下的,兼容到API17.
2、在xml布局中声明,在Java代码中初始化。
3、设置布局管理器
4、创建适配器,设置数据源,绑定适配器
具体创建适配器:①创建一个类,继承RecyclerView.Adapter
②创建一个类ViewHolder,继承RecyclerView。VIewHolder,该类需要创建一个匹配父类的构造。
③重写适配器中的方法:getItemCount():获取数据源的个数(item的数量);onCreateViewHolder():该方法中导入布局,实例化VIewHolder;onBindViewHolder():绑定VIewHolder,加载数据。
注意一点:RecyclerView的LinearLayoutManager不同于一般的适配器的布局,RecyclerView的item最外层的布局参数是有效的,如高度宽度等,所以在使用的时候,第一种方法是在导入View的时候指定没有parent(不推荐使用),第二种方法是在item布局的最外层指定具体的参数。
RecyclerView 为开发者提供了强大的复用机制,但是所有的点击事件都丢了,没有提供默认的点击事件,所以需要我们自己为RecyclerView手动实现点击。
多布局在JSON文件中一般有明确的区分,例如通过Type=1,2,3,4,等方式进行区分,Type=1,说明是一种类型的布局!
RecyclerView的使用场景:
多种样式的列表。
宫格和列表同时存在
分类列表(比如通讯录)
多布局的重点:
1、 复写getItemViewType(int position)
根据各个position的位置,返回不同的类型。
2、 处理getItemCount
3、 按照返回的类型处理onCreateViewHolder和onBindViewHolder方法
RecyclerView多种布局原理和机制::
多种布局保存!
RV中的关键成员:
Type <- getItemViewType(int position)
RecyclerView.Holder
RecyclerView.Recycler
Recycler中保存了一些缓存机制(类上与ListView中的conVertView)
多布局的设计流程
滚动 ----àgetItemViewType(position)------à根据Type寻找Holder-------àif(寻找Holder时返回null)-----àadpter.createViewHolder-----à否则adapter.bindViewHolder.
getItemViewType
ItemType保存在Holder中
Holder根据position被缓存在cache中
遍历缓存中的Holder,如果Type一致就返回。
当我们需要重复使用的时候,系统会在cache里面拿holder,进而实现使用流畅。
和ListView的区别
1. type已经是Holder的成员
2. RecyclerView的缓存单位是Holder而不在是View
3. RecyclerPool的缓存key是type
getItemViewtype(intposition)中的Type,只需要一个数字,不一定是连续的数字。
代码实现以及说明:
导入compile 'com.android.support:recyclerview-v7:26.+'
RecyclerView的依赖
DataModle:
package com.example.jash.recyclerview_more; import java.io.Serializable; public class DataModel implements Serializable { public static final int TYPE_ONE = 1; public static final int TYPE_TWO = 2; public static final int TYPE_THREE = 3; public int type; public int avatarColor; public String name; public String Content; public int contentColor; }
三个布局的XML:
First:
xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="60dp" android:gravity="center" android:orientation="horizontal"> <ImageView android:id="@+id/avatar" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginLeft="20dp" /> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" tools:text="aaaaa" /> LinearLayout>
Two:
xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="60dp" android:gravity="center" android:orientation="horizontal"> <ImageView android:id="@+id/zuozhe" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginLeft="20dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" tools:text="aaaaa" /> <TextView android:id="@+id/content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginTop="10dp" tools:text="aaaaa" /> LinearLayout> LinearLayout>
Three:
xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="60dp"> <ImageView android:layout_alignParentLeft="true" android:id="@+id/avatar" android:layout_width="40dp" android:layout_height="40dp" android:layout_centerVertical="true" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toRightOf="@+id/avatar" android:orientation="vertical"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" tools:text="aaaaa" /> <TextView android:id="@+id/content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginTop="10dp" tools:text="aaaaa" /> LinearLayout> <ImageView android:id="@+id/contentImage" android:layout_width="60dp" android:layout_height="60dp" android:layout_alignParentRight="true" android:layout_centerVertical="true"/> RelativeLayout>
抽象ViewHolder
import android.support.v7.widget.RecyclerView; import android.view.View; public abstract class TypeAbstrHolder extends RecyclerView.ViewHolder { public TypeAbstrHolder(View itemView) { super(itemView); } public abstract void bindHolder(DataModel model); }
三个ViewHolder 继承抽象ViewHolder
First: import android.graphics.Color; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.ImageView; import android.widget.TextView; public class TypeOneViewHolder extends TypeAbstrHolder { public ImageView avatar; public TextView name; public TypeOneViewHolder(View itemView) { super(itemView); avatar = (ImageView) itemView.findViewById(R.id.avatar); name = (TextView) itemView.findViewById(R.id.name); itemView.setBackgroundColor(Color.GREEN); } @Override public void bindHolder(DataModel model) { avatar.setBackgroundResource(model.avatarColor); name.setText(model.name); } }
Two:
import android.content.Context; import android.graphics.Color; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.ImageView; import android.widget.TextView; public class TypeTwoHolder extends TypeAbstrHolder { private ImageView zuozhe; private TextView name; private TextView content; public TypeTwoHolder(View itemView) { super(itemView); zuozhe = (ImageView) itemView.findViewById(R.id.zuozhe); name = (TextView) itemView.findViewById(R.id.name); content = (TextView) itemView.findViewById(R.id.content); itemView.setBackgroundColor(Color.BLACK); } @Override public void bindHolder(DataModel model) { zuozhe.setBackgroundResource(model.avatarColor); name.setText(model.name); content.setText(model.Content); } }
three:
import android.graphics.Color; import android.view.View; import android.widget.ImageView; import android.widget.TextView; public class TypeThreeViewHolder extends TypeAbstrHolder { private ImageView avatar; private TextView name; private TextView content; private ImageView contentColor; public TypeThreeViewHolder(View itemView) { super(itemView); avatar = (ImageView) itemView.findViewById(R.id.avatar); name = (TextView) itemView.findViewById(R.id.name); content = (TextView) itemView.findViewById(R.id.content); contentColor = (ImageView) itemView.findViewById(R.id.contentImage); itemView.setBackgroundColor(Color.GRAY); } @Override public void bindHolder(DataModel model) { avatar.setImageResource(model.avatarColor); name.setText(model.name); content.setText(model.Content); contentColor.setBackgroundResource(model.contentColor); } }
RecyclerView的Adapter
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; import java.util.concurrent.BrokenBarrierException; public class MyAdapter extends RecyclerView.Adapter{ private Context context; private List mList = new ArrayList<>(); private LayoutInflater inflater; protected MyAdapter(Context context) { this.context = context; inflater = LayoutInflater.from(context); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case DataModel.TYPE_ONE: return new TypeOneViewHolder(inflater.inflate(R.layout.one, parent, false)); case DataModel.TYPE_TWO: return new TypeTwoHolder(inflater.inflate(R.layout.two, parent, false)); case DataModel.TYPE_THREE: return new TypeThreeViewHolder(inflater.inflate(R.layout.three, parent, false)); } return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ((TypeAbstrHolder) holder).bindHolder(mList.get(position)); } @Override public int getItemViewType(int position) { return mList.get(position).type; } @Override public int getItemCount() { return mList.size(); } public void addList(List list) { mList.addAll(list); } }
MainActivity:
package com.example.jash.recyclerview_more; import android.graphics.Rect; import android.support.v4.view.GravityCompat; 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 java.util.ArrayList; import java.util.Date; import java.util.List; public class MainActivity extends AppCompatActivity { private RecyclerView mRecycler; private MyAdapter mAdapter; int color[] = {android.R.color.holo_orange_dark, android.R.color.holo_red_dark, android.R.color.holo_blue_bright}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecycler = (RecyclerView) findViewById(R.id.recycler); mRecycler.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false)); mAdapter = new MyAdapter(this); mRecycler.setAdapter(mAdapter); initData(); } private void initData() { Listlist = new ArrayList<>(); for (int i = 0; i < 30; i++) { int type; if (i < 5 || (i > 15 && i < 20)) { type = 1; } else if (i < 10 || i > 26) { type = 2; } else { type = 3; } Log.d("1", "initData: " + String.valueOf(type) + "=====>>>" + i); DataModel data = new DataModel(); data.avatarColor = color[type - 1]; data.type = type; data.name = "name" + i; data.Content = "conten" + type; data.contentColor = color[type - 1]; list.add(data); } mAdapter.addList(list); } }
mainXML:
xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.jash.recyclerview_more.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="match_parent" /> RelativeLayout>
实现的布局!
为列表类的还有三种不同的布局的显示
二、如何实现GridView和ListView同时显示!
MainActivity中:加入代码
final GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3);创建一个3列显示的GridView。
Log.d("1", "onCreate: " + gridLayoutManager.getSpanCount()); 该方法为合并GridView中的列 gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) {
//获取指定position上的itemView的type int type = mRecycler.getAdapter().getItemViewType(position);
//如果type==类型为3 的布局 if (type == DataModel.TYPE_THREE) {
//获取gridLayoutManager的列数,上面指定为3了,所有将3 合并成1,否则不合并 return gridLayoutManager.getSpanCount(); } else { return 1; } } });
//添加分隔线! mRecycler.addItemDecoration(new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) view.getLayoutParams();
//获取一行中含有多少个 View
int spanSize = layoutParams.getSpanSize();
// spanIndex ==1 为View的左侧 ==2 为View的右侧 int spanIndex = layoutParams.getSpanIndex(); outRect.top = 20; if (spanSize != gridLayoutManager.getSpanCount()) { outRect.left=3;
}
//切记一定要注释掉这行代码! // super.getItemOffsets(outRect, view, parent, state); } });
效果图: