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库
在activity_main.xml中加入RecyclerView
用法其实跟listView差不多
为RecyclerView的子项创建布局,名之为iterm.recycler.xml
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">
为了好看我用了CardView做为子项的根布局,注意它的用法,参加注释
@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是哪种布局,这里我直接使用线性布局
RecyclerView跟ListView一样,也需要适配器。这里我们写一个适配器类,继承RecyclerView.Adapter
public class AdapterForRecyclerVIew extends RecyclerView.Adapter {
private LinkedList urls = new LinkedList<>();
private LinkedList descriptions = new LinkedList<>();
private Context context = null;
private String TAG = "AdapterForRecyclerVIew";
public AdapterForRecyclerVIew(LinkedList urls,LinkedList 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中
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监听
回到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就行
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;
}
}
因为有多种子项,为了鉴别,我们最好定义一种枚举,来区分子项类型
private enum viewType {
TYPE_TEXT, TYPE_IMAGE;
}
为了获取子项类型,我们需要覆写父类种getItemViewType()方法
@Override
public int getItemViewType(int position) {
if (position == 0 || position == urls.size() + 1) {
return viewType.TYPE_TEXT.ordinal();
}
return viewType.TYPE_IMAGE.ordinal();
}
这时我们要多显示两项,所以返回值要+2
@Override
public int getItemCount() {
return urls.size() + 2;
}
根据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