默认的Adapter :
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return 0;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
}
}
要写出一个RecyclerView.Adapter必须自己写一个ViewHolder且一定要继承RecyclerView.ViewHolder;然后重写onCreateViewHolder、onBindViewHolder、getItemCount这三个函数
而其他几个函数都基本上都是固定格式了,所以我们就可以将这些千篇一律的代码进行封装了。
Adapter中我们最终要的一个就是数据源了,所以我们需要先定义我们的数据源但是你会发现在不同的地方
我们的数据也是不一样的那我们怎么定义呢?这个时候我们就需要引入泛型了。
1.RecycleVIew定义在support库中,所以要想使用这个控件,需要在build.grade中添加相应的依赖库。(记得Sync now同步)
2.activity_main.xml中
为RecyclerView指定一个id,宽高都为match_parent,这样就使RecycleView铺满整个布局空间。
(因为RecycleView不是内置系统Sdk当中的,所以需要把他的完整路径写下来)
3.同ListView的例子一样写一个Fruit类和fruit_item.xml,并将所需水果图复制过来。
4.为RecycleView准备一个适配器
(作用:把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作)
关于适配器的详细介绍博推荐:https://blog.csdn.net/carson_ho/article/details/54910430
(关于泛型的定义:https://blog.csdn.net/a_zhon/article/details/66971369)
默认的Adapter
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return 0;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
}
}
FruitAdapter.java
新建FruitAdapter类,让这个适配器继承自RecycleView.Adapter,并将泛型指定为FruitAdapter.Viewholder。其中,ViewHolder是在FruitAdapter定义的一个内部类。
代码如下:
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private List<Fruit> myFruitList;
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView fruitImage;
TextView fruitName;
public ViewHolder(View view) {
super(view);
fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
fruitName = (TextView) view.findViewById(R.id.fruit_name);
}
}
public FruitAdapter(List<Fruit> fruitList) {
myFruitList = fruitList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Fruit fruit = myFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}
@Override
public int getItemCount() {
return myFruitList.size();
}
}
1.首先定义一个内部类ViewHolder,VIewHolder首先要继承RecycleView.ViewHolder。ViewHolder的构造函数要传入一个View参数,通常就是RecycleView子项的最外层布局
2.FruitAdapter中也存在一个构造函数,
public FruitAdapter(List< Fruit> fruitList) {
myFruitList = fruitList;
}
这个方法用于把要展示的数据源传进来,并赋值给全局变量mFruitList
3.重写三个方法
onCreateViewHolder()创建ViewHolder实例,把加载出来的布局传入到构造函数当中,最后将ViewHolder的实力返回
onBindViewHolder()用于对子项数据进行赋值,通过position得到当前Fruit实例,然后再将数据设置到ViewHolder的ImageView和TextView当中
getItemCount()告诉RecycleView一共有多少个子项,直接返回数据源长度就可以了。
5.MainActivity.java
public class MainActivity extends Activity {
private List<Fruit> fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();
RecyclerView recyclerView=(RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
FruitAdapter adapter=new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
}
private void initFruits() {
Fruit apple = new Fruit("apple", R.drawable.apple);
fruitList.add(apple);
Fruit pear = new Fruit("apple", R.drawable.pear);
fruitList.add(pear);
Fruit pineapple = new Fruit("apple", R.drawable.pineapple);
fruitList.add(pineapple);
Fruit kiwi = new Fruit("apple", R.drawable.kiwi);
fruitList.add(kiwi);
Fruit grapes = new Fruit("apple", R.drawable.grapes);
fruitList.add(apple);
Fruit raspberry = new Fruit("apple", R.drawable.raspberry);
fruitList.add(raspberry);
Fruit straberry = new Fruit("apple", R.drawable.straberry);
fruitList.add(straberry);
}
}
注:1.为什么是List list = new ArrayList(),而不直接用ArrayList
(1) List list = new ArrayList();
这样你就只能调用List接口里面定义好的方法,而不能使用你自己在ArrayList扩展的方法。
(2) ArrayList list = new ArrayList();
这样你可以使用自己在ArrayList类上扩展的方法
接口就是定义了一些行为,它要求你应该做什么。 假如你采用了面向接口编程方式,也就是第一种方式:
List list = new ArrayList(); 就能通过接口很大限度上规范开发人员的实现规则,因为你现在只能调用接口的方法。
1.initFruits() 用于初始化所有水果数据
2.onCreate()方法中休闲获取RecycleView的实例
3.创建一个LinearLayoutManager对象,并将它设置到RecycleView当中。
4.创建FruitAdapter的实例并将水果数据传入到构造函数之中
5.调用RecycleView的setAdapter()方法来完成适配器设置
以上面的例子修改:
MainActivity.java 中只加入
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
调用LinearLayoutManager的setOrientation()方法来设置布局的排列方向,默认是纵向排列的,我们把它修改为LinearLayoutManager.HORIZONTAL
RecycleView将工作交给LayoutManager,LayoutManager中制定了一套可扩展的布局排列接口,子类只要按照接口的规范来实现,就可以制定出各种不同的布局了。
StaggeredGridLayoutManager layoutManager=new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
在onCreate()方法中创建一个StaggeredGridLayoutManager的实例,StaggeredGridLayoutManager的构造函数接收两个参数,第一个参数用于指定布局的列数,第二个参数用于指定布局的排列方向。
这里在写入一个getRandomLengthName()方法,实现更好的瀑布效果
private String getRandomLengthName(String name){
Random random=new Random();
int length=random.nextInt(20)+1;
StringBuilder builder=new StringBuilder();
for(int i=0;i<length;i++){
builder.append(name);
}
return builder.toString();
}
注:
(1)nextInt(int n) 方法用于获取一个伪随机,在0(包括)和指定值(不包括),从此随机数生成器的序列中取出均匀分布的int值。
(2)StringBuffer 方法:
以下是 StringBuffer 类支持的主要方法:
1 public StringBuffer append(String s)
将指定的字符串追加到此字符序列。
2 public StringBuffer reverse()
将此字符序列用其反转形式取代。
3 public delete(int start, int end)
移除此序列的子字符串中的字符。
4 public insert(int offset, int i)
将 int 参数的字符串表示形式插入此序列中。
5 replace(int start, int end, String str)
使用给定 String 中的字符替换此序列的子字符串中的字符。
修改ViewHolder,在ViewHolder中添加fruitView变量来保存子项最外层实例,然后在onCreateViewHolder()方法中注册点击事件。这里分别在最外层布局和ImageView都注册点击事件。
在两个事件中先获取用户的点击的position,然后通过position拿到相应的Fruit实例,再分别使用Toast分别弹出两种不同内容以示区别。
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
final ViewHolder holder=new ViewHolder(view);
holder.fruitView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position=holder.getAdapterPosition();
Fruit fruit=myFruitList.get(position);
Toast.makeText(v.getContext(),"you clicked view"+fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
holder.fruitImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position=holder.getAdapterPosition();
Fruit fruit=myFruitList.get(position);
Toast.makeText(v.getContext(),"you clicked image"+fruit.getImageId(),Toast.LENGTH_SHORT).show();
}
});
return holder;
}