介绍
RecyclerView是一种高级的ListView,以后可以用它来代替ListView
CardView则是一种更好看的视图,使用比较简单,这里我把他俩放在一起介绍
基本使用步骤
导入依赖
我们得先导入RecyclerView和CardView的依赖
compile 'com.android.support:recyclerview-v7:26.0.0'
compile 'com.android.support:cardview-v7:26.0.0'
//recyclerView和cardView库
在主布局中加入RecyclerView
在activity_main.xml中加入RecyclerView
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
用法其实跟listView差不多
创建item的布局
为RecyclerView的子项创建布局,名之为iterm.recycler.xml
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto" <!-- 注意cardView的命名空间 -->
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="4dp" <!-- 设置卡片四个角的弧度半径 -->
android:layout_margin="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="90dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_img"
android:layout_weight="1"
android:layout_width="90dp"
android:gravity="center"
android:layout_height="match_parent" />
<TextView
android:id="@+id/tv_img"
android:layout_weight="1"
android:layout_width="50dp"
android:gravity="center"
android:layout_height="match_parent" />
<Button
android:id="@+id/btn_img"
android:text="这是哪个队"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</LinearLayout>
</android.support.v7.widget.CardView>
为了好看我用了CardView做为子项的根布局,注意它的用法,参加注释
在MainActivity中设置RecyclerView
@BindView(R.id.rv_recycler)
RecyclerView recyclerView;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activty_main);
ButterKnife.bind(this);
recyclerView.setLayoutManager(new LinearLayoutManager(this)); // 设置线性布局
...
}
我使用了ButterKnife来初始化控件(其实就是findViewById()),现在先不管他,以后再介绍用法
通过recyclerView.setLayoutManager()可以指定recyclerView是哪种布局,这里我直接使用线性布局
构造Adapter类
RecyclerView跟ListView一样,也需要适配器。这里我们写一个适配器类,继承RecyclerView.Adapter
public class AdapterForRecyclerVIew extends RecyclerView.Adapter {
private LinkedList<String> urls = new LinkedList<>();
private LinkedList<String> descriptions = new LinkedList<>();
private Context context = null;
private String TAG = "AdapterForRecyclerVIew";
public AdapterForRecyclerVIew(LinkedList<String> urls,LinkedList<String> descriptions, Context context) {
this.urls = urls;
this.descriptions = descriptions;
this.context = context;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
CardView layout = (CardView) LayoutInflater.from(context).inflate(R.layout.item_recycler, parent, false); // 要inflate子项的根节点 carView
return new MyViewHolderForImage(layout);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
MyViewHolderForImage holderForImage = (MyViewHolderForImage) holder;
Picasso.with(context).load(urls.get(position - 1)).into(holderForImage.getImageView());
holderForImage.getTextView().setText(descriptions.get(position - 1));
}
@Override
public int getItemCount() {
return urls.size();
}
}
里面的三个方法onCreateViewHolder()、onBindViewHolder()、getItemCount()都是我们必须要实现的。
其中onCreateViewHolder()用来创建子项的viewHolder,所以我们要新建一个ViewHolder类,继承RecyclerView.ViewHolder,这个ViewHolder里面就是子项的所有控件,子项的UI逻辑,都放在ViewHolder中,可以作为mvp设计模式中的presenter(代码下一步再说)
onBindViewHolder()则是加载子项viewHolder的内容,参数里面的holder就是上一个方法onCreateViewHolder()中返回过来的
getItemCount()方法决定了recyclerView要显示多少个子项
创建ViewHolder类
根据上一步说的,我们把子项逻辑都放在ViewHolder中
public class MyViewHolderForImage extends RecyclerView.ViewHolder {
@BindView(R.id.iv_img) ImageView imageView;
@BindView(R.id.tv_img) TextView textView;
public MyViewHolderForImage(View itemView) {
super(itemView);
ButterKnife.bind(this,itemView); // 根据adapter中的onCreateViewHolder(),这里传进来的itermView就是cardView
textView.setVisibility(View.INVISIBLE);
}
@OnClick(R.id.btn_img)
public void changeVisibility(){
textView.setVisibility(View.VISIBLE);
}
public ImageView getImageView() {
return imageView;
}
public TextView getTextView() {
return textView;
}
}
还是用了ButterKnife绑定控件,设置onClick监听
为recyclerView设置adapter,并初始化数据
回到onCreate(),设置一下adapter,并赋予一些数据
adapter = new AdapterForRecyclerVIew(urls, descriptions, this);
addUrls();
addDescriptions();
recyclerView.setAdapter(adapter);
private void addDescriptions() {
descriptions.add("南部之星拜仁慕尼黑");
descriptions.add("骄傲的大黄蜂多特蒙德");
descriptions.add("红魔曼联");
descriptions.add("蓝军切尔西");
}
private void addUrls() {
urls.add("http://n.sinaimg.cn/sports/transform/20170216/1s3V-fyarzzv2801842.jpg");
urls.add("http://www.zq1.com/Upload/20170415/235459msc9i5yiqracirfw.jpg");
urls.add("http://k.sinaimg.cn/n/sports/transform/20160424/dfCS-fxrqhar9877773.JPG/w570fe9.jpg");
urls.add("http://n.sinaimg.cn/sports/transform/20170423/L9Uj-fyeqcac1387497.jpg");
}
由于我是先设置数据,再设置适配,所以不用notifyDataSetChanged()
效果
ok,这就是recyclerView的基本用法
多种类型子项混排
可以看到,在录屏gif种,最上面最下面是文字,而这些文字也是RecyclerView的子项,怎么实现呢?只需要增加相应子项的布局文件和对应ViewHolder、再改变一下adapter就行
添加新子项的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/tv_item"
android:gravity="center"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
添加新子项的viewHolder
public class MyViewHolderForText extends RecyclerView.ViewHolder {
@BindView(R.id.tv_item) TextView textView;
public MyViewHolderForText(View itemView) {
super(itemView);
ButterKnife.bind(this,itemView);
}
public TextView getTextView() {
return textView;
}
}
更改adapter
添加子项类型枚举
因为有多种子项,为了鉴别,我们最好定义一种枚举,来区分子项类型
private enum viewType {
TYPE_TEXT, TYPE_IMAGE;
}
覆写getItemViewType方法
为了获取子项类型,我们需要覆写父类种getItemViewType()方法
@Override
public int getItemViewType(int position) {
if (position == 0 || position == urls.size() + 1) {
return viewType.TYPE_TEXT.ordinal();
}
return viewType.TYPE_IMAGE.ordinal();
}
修改getItemCount方法
这时我们要多显示两项,所以返回值要+2
@Override
public int getItemCount() {
return urls.size() + 2;
}
修改onCreateViewHolder方法和onBindViewHolder方法
根据viewType来获取不同的viewHolder或执行不同逻辑
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == AdapterForRecyclerVIew.viewType.TYPE_IMAGE.ordinal()) {
CardView layout = (CardView) LayoutInflater.from(context).inflate(R.layout.item_recycler, parent, false);
return new MyViewHolderForImage(layout);
} else {
LinearLayout layout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.text_item_recycler, parent, false);
return new MyViewHolderForText(layout);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == viewType.TYPE_IMAGE.ordinal()) {
MyViewHolderForImage holderForImage = (MyViewHolderForImage) holder;
Picasso.with(context).load(urls.get(position - 1)).into(holderForImage.getImageView()); // 因为第一个是textView,所以url的索引是position-1
holderForImage.getTextView().setText(descriptions.get(position - 1));
} else {
((MyViewHolderForText) holder).getTextView().setText("宋泽嶒");
}
}
这样,就大功告成了
结语
RecyclerView可以帮助我们更好地实现mvp,也是一种性能更好的listView