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>.
②创建一个类ViewHolder,继承RecyclerView。VIewHolder,该类需要创建一个匹配父类的构造。
③重写适配器中的方法:getItemCount():获取数据源的个数(item的数量);onCreateViewHolder():该方法中导入布局,实例化VIewHolder;onBindViewHolder():绑定VIewHolder,加载数据。
注意一点:RecyclerView的LinearLayoutManager不同于一般的适配器的布局,RecyclerView的item最外层的布局参数是有效的,如高度宽度等,所以在使用的时候,第一种方法是在导入View的时候指定没有parent(不推荐使用),第二种方法是在item布局的最外层指定具体的参数。
RecyclerView 为开发者提供了强大的复用机制,但是所有的点击事件都丢了,没有提供默认的点击事件,所以需要我们自己为RecyclerView手动实现点击。
看一个简单的例子,后面讲解下多布局的RecyclerView。效果图如下(不要吐槽,我知道很丑,能达到效果就好^_^):

第一步:创建布局,需要导入依赖包:android.support.v7.widget.RecyclerView
activity_main.xml
<?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="match_parent" tools:context="com.zcl.day40_recyleview01.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/teach_recycler" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:background="@drawable/backgroud_shap" android:layout_height="match_parent"> <ImageView android:src="@mipmap/ic_launcher" android:layout_width="80dp" android:layout_height="80dp" /> <TextView android:id="@+id/teach_item_name" android:gravity="center" android:layout_width="match_parent" android:layout_height="80dp" /> </LinearLayout>
Model.java
public class Model { private String name; private int height; public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
MainActivity.java
public class MainActivity extends AppCompatActivity implements RecyclerAdapter.OnItemClickListener { private static final String TAG = MainActivity.class.getSimpleName(); private RecyclerView mRecyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { mRecyclerView = (RecyclerView) findViewById(R.id.teach_recycler); //设置布局管理器 //1、第一种LinearLayoutManager // LinearLayoutManager layoutManager = new LinearLayoutManager(this); //2、第二种 GridLayoutManager // GridLayoutManager layoutManager=new GridLayoutManager(this,3); //3、第三种 StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); // //设置布局的排版方向 // layoutManager.setOrientation(GridLayoutManager.HORIZONTAL); mRecyclerView.setLayoutManager(layoutManager); //绑定适配器 RecyclerAdapter adapter = new RecyclerAdapter(this, getData()); mRecyclerView.setAdapter(adapter); adapter.setOnItemClickListener(this);//将接口传递到数据产生的地方 } /** * 获取数据源 * * @return */ public List<Model> getData() { List<Model> data = new ArrayList<>(); for (int i = 0; i < 30; i++) { Model model = new Model(); model.setName("猴子请来的都比---" + i); model.setHeight(((int) (Math.random() * 100 + 200))); data.add(model); } return data; } @Override public void onItemClick(int position, Model model) { Log.e(TAG, "onItemClick: " + position); } }
适配器
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> implements View.OnClickListener { private static final String TAG = RecyclerAdapter.class.getSimpleName(); private List<Model> data; private LayoutInflater inflater; private RecyclerView mRecyclerView;//用来计算Child位置 private OnItemClickListener onItemClickListener; //对外提供接口初始化方法 public void setOnItemClickListener(OnItemClickListener onItemClickListener){ this.onItemClickListener=onItemClickListener; } public RecyclerAdapter(Context context,List<Model> data) { this.data = data; inflater= (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public static class ViewHolder extends RecyclerView.ViewHolder{ TextView name; public ViewHolder(View itemView) { super(itemView); name= (TextView) itemView.findViewById(R.id.teach_item_name); } } /** * 创建VIewHolder,导入布局,实例化itemView * @param parent * @param viewType * @return */ @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = inflater.inflate(R.layout.item, parent, false); //导入itemView,为itemView设置点击事件 itemView.setOnClickListener(this); return new ViewHolder(itemView); } /** * 绑定VIewHolder,加载数据 * @param holder * @param position */ @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.name.setText(data.get(position).getName());//加载数据 ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams(); layoutParams.height=data.get(position).getHeight(); holder.itemView.setLayoutParams(layoutParams); } /** * 数据源的数量,item的个数 * @return */ @Override public int getItemCount() { return data!=null?data.size():0; } /** * 适配器绑定到RecyclerView 的时候,回将绑定适配器的RecyclerView 传递过来 * @param recyclerView */ @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); mRecyclerView=recyclerView; } /** * * @param v 点击的View */ @Override public void onClick(View v) { //RecyclerView可以计算出这是第几个Child int childAdapterPosition = mRecyclerView.getChildAdapterPosition(v); Log.e(TAG, "onClick: "+childAdapterPosition ); if (onItemClickListener!=null) { onItemClickListener.onItemClick(childAdapterPosition,data.get(childAdapterPosition)); } } /** * 接口回调 * 1、定义接口,定义接口中的方法 * 2、在数据产生的地方持有接口,并提供初始化方法,在数据产生的时候调用接口的方法 * 3、在需要处理数据的地方实现接口,实现接口中的方法,并将接口传递到数据产生的地方 */ public interface OnItemClickListener{ void onItemClick(int position,Model model); } }
多布局的RecyclerView ---------------------------------------------------------------
先看下效果图:
这是
分析下该页面布局,三种布局,第一种是标题文字+内容简介文字占一个item,第二种是图片+标题占一个item,第三种是标题+内容,并且一个item中有两个这样的布局。那么可以用网格布局,分为两列,第一种跟第二种布局各自占两列,第三种布局占一列。那么怎么设置item可以横跨两列呢,就要用到gridLayoutManager.setSpanSizeLookup来设置,具体看代码:
activity_main.xml
<?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.zcl.day40_task2.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout>
item1.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="200dp"> <ImageView android:id="@+id/iv_item1" android:src="@mipmap/ic_launcher" android:layout_width="match_parent" android:layout_height="200dp" /> <TextView android:id="@+id/tv_item1" android:text="title" android:textColor="#e5ffffff" android:textSize="20sp" android:textStyle="bold" android:layout_marginLeft="15dp" android:layout_marginTop="20dp" android:layout_marginRight="15dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout>
item2.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="200dp"> <TextView android:id="@+id/tv_item2_title" android:textSize="20sp" android:textStyle="bold" android:text="title" android:layout_marginLeft="15dp" android:layout_marginTop="20dp" android:layout_marginRight="15dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/tv_item2_content" android:layout_marginLeft="15dp" android:layout_marginTop="10dp" android:text="content" android:layout_marginBottom="10dp" android:layout_marginRight="15dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
item3.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="200dp"> <TextView android:id="@+id/tv_item3_title" android:textSize="20sp" android:lines="2" android:ellipsize="end" android:text="title" android:layout_marginLeft="15dp" android:layout_marginTop="10dp" android:layout_marginRight="15dp" android:layout_width="match_parent" android:layout_height="60dp" /> <TextView android:id="@+id/tv_item3_content" android:lines="2" android:ellipsize="end" android:text="content" android:layout_marginLeft="15dp" android:layout_marginTop="10dp" android:layout_marginRight="15dp" android:layout_width="match_parent" android:layout_height="60dp" /> </LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity implements MyAdapter.OnItemClickLietener{ private static final String TAG = MainActivity.class.getSimpleName(); private RecyclerView mRecyclerView; private MyAdapter adapter; private List<Model> data; public static final String URL_PATH="http://dxy.com/app/i/feed/index/list?hardName=Google%20Nexus%205%20-%205.1.0%20-%20API%2022%20-%201080x1920&u=&bv=2015&ac=d5424fa6-adff-4b0a-8917-4264daf4a348&vc=5.1.9&vs=5.1&mc=00000000600ba4e6ffffffff99d603a9"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { ImageLoader.init(this); mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); //设置布局管理器 GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2); Log.e(TAG, "initView:----1 " ); gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { int spansize=1; switch (adapter.getItemViewType(position)) { case 1: spansize=2; break; case 2: spansize=2; break; } return spansize; } }); Log.e(TAG, "initView: -----2" ); mRecyclerView.setLayoutManager(gridLayoutManager); adapter = new MyAdapter(this, getData()); mRecyclerView.setAdapter(adapter); adapter.setClickLietener(this); Log.e(TAG, "initView: 4" ); } public List<Model> getData() { Log.e(TAG, "getData: 3" ); HttpUtil.getStringAsync(URL_PATH, new HttpUtil.RequestCallBack() { @Override public void onFailure() { Log.e(TAG, "onFailure: " ); } @Override public void onSuccess(String result) { Gson gson = new Gson(); ModelData modelData = gson.fromJson(result, ModelData.class); List<Model> data =modelData.getData().getItems(); Log.e(TAG, "onSuccess: "+data ); adapter.addRes(data); } @Override public void onFinish() { Log.e(TAG, "onFinish: " ); } }); return data; } @Override public void setItemClickListener(int position) { Log.e(TAG, "setItemClickListener: "+position ); } }
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> implements View.OnClickListener { private List<Model> data; private LayoutInflater inflater; private RecyclerView mRecyclerView; private OnItemClickLietener clickLietener; public void setClickLietener(OnItemClickLietener clickLietener){ this.clickLietener=clickLietener; } public MyAdapter(Context context, List<Model> data) { this.data = data; inflater = LayoutInflater.from(context); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = null; switch (viewType) { case 1: itemView = inflater.inflate(R.layout.item1, parent, false); break; case 2: itemView = inflater.inflate(R.layout.item2, parent, false); break; case 8: itemView = inflater.inflate(R.layout.item3, parent, false); break; //设置监听 } itemView.setOnClickListener(this); return new ViewHolder(itemView); } @Override public void onBindViewHolder(ViewHolder holder, int position) { switch (getItemViewType(position)) { case 1: ImageView imageView = (ImageView) holder.getView(R.id.iv_item1); TextView textView = (TextView) holder.getView(R.id.tv_item1); textView.setText(data.get(position).getTitle()); String picPath = data.get(position).getCover(); ImageLoader.display(imageView, picPath); break; case 2: TextView item2Title = (TextView) holder.getView(R.id.tv_item2_title); TextView item2Content = (TextView) holder.getView(R.id.tv_item2_content); item2Title.setText(data.get(position).getTitle()); item2Content.setText(data.get(position).getContent()); break; case 8: TextView item3Title = (TextView) holder.getView(R.id.tv_item3_title); TextView item3Content = (TextView) holder.getView(R.id.tv_item3_content); item3Title.setText(data.get(position).getTitle()); item3Content.setText(data.get(position).getContent()); break; } } @Override public int getItemCount() { return data != null ? data.size() : 0; } @Override public int getItemViewType(int position) { return data.get(position).getShow_type(); } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); mRecyclerView=recyclerView; } public void addRes(List<Model> data) { if (data != null) { this.data = data; notifyDataSetChanged(); } } @Override public void onClick(View v) { int childAdapterPosition = mRecyclerView.getChildAdapterPosition(v); if (clickLietener!=null) { clickLietener.setItemClickListener(childAdapterPosition); } } public static class ViewHolder extends RecyclerView.ViewHolder { private Map<Integer, View> mCacheView; public ViewHolder(View itemView) { super(itemView); mCacheView = new HashMap<>(); } public View getView(int resId) { View view; if (mCacheView.containsKey(resId)) { view = mCacheView.get(resId); } else { view = itemView.findViewById(resId); mCacheView.put(resId, view); } return view; } } public interface OnItemClickLietener{ void setItemClickListener(int position); } }
代码中使用的网络数据的请求以及图片的加载是自己封装的类库,大家可以忽略,用自己的代码填充,能理解RecyclerView就好,另外数据的实体类太简单,也没有贴上代码。最后不要忘了配置网络权限哦。
我的github:https://github.com/SiberiaDante