更强大的滚动控件—RecyclerView
RecyclerView的基本用法
-
ListView的扩展性和性能比较差,需要做一些技巧来提升他的效率,而且他是能实现数据的纵向滚动,并不能横向滚动
-
RecyclerView是一个增强版的ListView,可以轻松实现ListView同样的效果,还优化了ListView的不足之处
//首先在项目的build.gradle中添加相应的依赖库 //打开app/build.gradle,在dependencies闭包中添加以下内容,添加完之后点击Sync Now进行同步 dependencies { implementation fileTree(dir: 'libs',includes: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.0.0' implementation 'androidx.recyclerview:recyclerview:1.0.0' testImplementation 'junit:junit:4.12' } //修改activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> //由于RecyclerView并不是内置在系统SDK中,所以需要把完整的包路径写出来 <androidx.recyclerview.widget.RecyclerView android:id="@+id/relative_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout> //将写在ListView项目的Fruit类和fruit_item.xml也复制过来,接下来为RecyclerView准备一个适配器,新建FruitAdapter类,让其继承自RecursiveAction.Adapter, ViewHolder是在FruitAdapter中定义的一个内置类 public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> { //定义一个全局变量 private List<Fruit> mFruitList; //定义一个内部类ViewHolder,ViewHolder要继承RecyclerView.ViewHolder static class ViewHolder extends RecyclerView.ViewHolder{ ImageView fruitImage; TextView fruitName; //构造函数中要传入一个View参数,这个参数通常是RecyclerView子项的最外层布局, // 那么就可以通过findViewById()方法来获取到不居中的ImageView和TextView的实例了 public ViewHolder(View view){ super(view); fruitImage = (ImageView) view.findViewById(R.id.fruit_image); fruitName = (TextView) view.findViewById(R.id.fruit_name); } } //FruitAdapter中也有一个构造函数,这个方法用于把展示的数据源传进来,并赋值给一个全局变量mFruitList,后 续操作都在这个数据源上进行 public FruitAdapter(List<Fruit> fruitList){ mFruitList = fruitList; } //由于RecyclerView继承自RecyclerView.Adapter,那么就必须重写onCreateViewHolder(),onBindViewHolder(),getItemCount()方法 //onCreateViewHolder()方法用于创建ViewHolder实例, //在这个方法内将fruit_item布局加载进来,然后创建一个ViewHolder实例,并将加载出来的布局传入构造函数中, 最后将ViewHolder实例返回 @Override public ViewHolder onCreateViewHolder( ViewGroup parent, int viewType) { View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false); ViewHolder holder = new ViewHolder(view); return holder; } //onBindViewHolder()方法是用于对RecyclerView子项的数据进行赋值的,会在每个子项被滚动到屏幕内的时候执行, // 这里通过position参数的到当前项的Friut实例,然后再将数据设置到ViewHolder的ImageView和TextView中 @Override public void onBindViewHolder(ViewHolder holder, int position) { Fruit fruit = mFruitList.get(position); holder.fruitImage.setImageResource(fruit.getImageId()); holder.fruitName.setText(fruit.getName()); } //getItemCount()方法用于告诉RecyclerView一共有多少子项,直接返回数据源的长度 @Override public int getItemCount() { return mFruitList.size(); } } //修改MainActivity,使用RecyclerView public class MainActivity extends AppCompatActivity { 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.relative_view); //创建一个LinearLayoutManager对象并将他设置到RecyclerView中,LayoutManager用于制定布局方式,LinearLayoutManager是线性布局的意思,可以实现与ListView相似的效果 LinearLayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); //创建FruitAdapter实例,并将水果数据传入FruitAdapter的构造函数中 FruitAdapter adapter = new FruitAdapter(fruitList); //最后调用setAdapter()方法完成适配器设置 recyclerView.setAdapter(adapter); } private void initFruits(){ for (int i = 0;i<2;i++){ Fruit apple = new Fruit("Apple",R.drawable.apple); fruitList.add(apple); Fruit banner = new Fruit("Banner",R.drawable.banner); fruitList.add(banner); Fruit orange = new Fruit("Orange",R.drawable.orange); fruitList.add(orange); Fruit watermelon = new Fruit("Watermelon",R.drawable.watermelon); fruitList.add(watermelon); Fruit pear = new Fruit("Pear",R.drawable.pear); fruitList.add(pear); Fruit grape = new Fruit("Grape",R.drawable.grape); fruitList.add(grape); Fruit pineapple = new Fruit("Pineapple",R.drawable.pineapple); fruitList.add(pineapple); Fruit strawberry = new Fruit("Strawberry",R.drawable.strawberry); fruitList.add(strawberry); Fruit cherry = new Fruit("Cherry",R.drawable.cherry); fruitList.add(cherry); Fruit mango = new Fruit("Mango",R.drawable.mango); fruitList.add(mango); } } }
-
运行结果
实现横向滚动和瀑布流布局
横向滚动
//修改布局fruit_item.xml,将元素改为垂直排列
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center_horizontal" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="10dp" />
</LinearLayout>
//修改MainActivity,调用LinearLayoutManager的setOrientation()方法来设置布局的排列方向,默认是纵向,传入LinearLayoutManager.HORIZONTAL表示让布局横向排列
public class MainActivity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();
RecyclerView recyclerView = findViewById(R.id.relative_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
FruitAdapter adapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
}
private void initFruits(){
for (int i = 0;i<2;i++){
Fruit apple = new Fruit("Apple",R.drawable.apple);
fruitList.add(apple);
Fruit banner = new Fruit("Banner",R.drawable.banner);
fruitList.add(banner);
Fruit orange = new Fruit("Orange",R.drawable.orange);
fruitList.add(orange);
Fruit watermelon = new Fruit("Watermelon",R.drawable.watermelon);
fruitList.add(watermelon);
Fruit pear = new Fruit("Pear",R.drawable.pear);
fruitList.add(pear);
Fruit grape = new Fruit("Grape",R.drawable.grape);
fruitList.add(grape);
Fruit pineapple = new Fruit("Pineapple",R.drawable.pineapple);
fruitList.add(pineapple);
Fruit strawberry = new Fruit("Strawberry",R.drawable.strawberry);
fruitList.add(strawberry);
Fruit cherry = new Fruit("Cherry",R.drawable.cherry);
fruitList.add(cherry);
Fruit mango = new Fruit("Mango",R.drawable.mango);
fruitList.add(mango);
}
}
}
瀑布流布局
//修改fruit_item布局,使用layout_margin属性让子项之间互留间距,TextView对其属性改为居左对齐
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="5dp"
>
<ImageView
android:id="@+id/fruit_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center_horizontal" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="10dp" />
</LinearLayout>
//修改MainActivity
public class MainActivity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();
RecyclerView recyclerView = findViewById(R.id.relative_view);
//创建StaggeredGridLayoutManager实例。StaggeredGridLayoutManager的构造函数接收两个参数,第一个是布局的列数,第二个是布局的排列方向,StaggeredGridLayoutManager.VERTICAL是让布局纵向排列
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
//吧创建好的实例设置到RecyclerView中
recyclerView.setLayoutManager(layoutManager);
FruitAdapter adapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
}
private void initFruits(){
for (int i = 0;i<2;i++){
Fruit apple = new Fruit(getRandomLengthName("Apple"),R.drawable.apple);
fruitList.add(apple);
Fruit banner = new Fruit(getRandomLengthName("Banner"),R.drawable.banner);
fruitList.add(banner);
Fruit orange = new Fruit(getRandomLengthName("Orange"),R.drawable.orange);
fruitList.add(orange);
Fruit watermelon = new Fruit(getRandomLengthName("Watermelon"),R.drawable.watermelon);
fruitList.add(watermelon);
Fruit pear = new Fruit(getRandomLengthName("Pear"),R.drawable.pear);
fruitList.add(pear);
Fruit grape = new Fruit(getRandomLengthName("Grape"),R.drawable.grape);
fruitList.add(grape);
Fruit pineapple = new Fruit(getRandomLengthName("Pineapple"),R.drawable.pineapple);
fruitList.add(pineapple);
Fruit strawberry = new Fruit(getRandomLengthName("Strawberry"),R.drawable.strawberry);
fruitList.add(strawberry);
Fruit cherry = new Fruit(getRandomLengthName("Cherry"),R.drawable.cherry);
fruitList.add(cherry);
Fruit mango = new Fruit(getRandomLengthName("Mango"),R.drawable.mango);
fruitList.add(mango);
}
}
//设置名称长短随机
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();
}
}
- 运行结果
RecyclerView的点击事件
//修改FruitAdapter
//为RecyclerView准备一个适配器,新建FruitAdapter类,让这个适配器继承自RecursiveAction.Adapter
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
//定义一个全局变量
private List<Fruit> mFruitList;
//定义一个内部类ViewHolder,ViewHolder要继承RecyclerView.ViewHolder
static class ViewHolder extends RecyclerView.ViewHolder{
View fruitView; //添加fruitView变量来保存子项最外层布局的实例,然后在onCreateViewHolder()方法中注册点击事件
ImageView fruitImage;
TextView fruitName;
//构造函数中要传入一个View参数,这个参数通常是RecyclerView子项的最外层布局,
// 那么就可以通过findViewById()方法来获取到不居中的ImageView和TextView的实例了
public ViewHolder(View view){
super(view);
fruitView = view;
fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
fruitName = (TextView) view.findViewById(R.id.fruit_name);
}
}
//FruitAdapter中也有一个构造函数,这个方法用于把展示的数据源传进来,并赋值给一个全局变量mFruitList,后续操作都在这个数据源上进行
public FruitAdapter(List<Fruit> fruitList){
mFruitList = fruitList;
}
//由于RecyclerView继承自RecyclerView.Adapter,那么就必须重写onCreateViewHolder(),onBindViewHolder(),getItemCount()方法
//onCreateViewHolder()方法用于创建ViewHolder实例,
//在这个方法内将fruit_item布局加载进来,然后创建一个ViewHolder实例,并将加载出来的布局传入构造函数中,最后将ViewHolder实例返回
@Override
public ViewHolder onCreateViewHolder( ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
final ViewHolder holder = new ViewHolder(view);
//以下两个点击事件中先获取了用户点击的position,然后通过position拿到相应的Fruit实例
//为最外层布局注册点击事件
holder.fruitView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.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 = mFruitList.get(position);
Toast.makeText(v.getContext(),"you clicked image" + fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
return holder;
}
//onBindViewHolder()方法是用于对RecyclerView子项的数据进行赋值的,会在每个子项被滚动到屏幕内的时候执行,
// 这里通过position参数的到当前项的Friut实例,然后再将数据设置到ViewHolder的ImageView和TextView中
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}
//getItemCount()方法用于告诉RecyclerView一共有多少子项,直接返回数据源的长度
@Override
public int getItemCount() {
return mFruitList.size();
}
}
- 运行结果