我们知道,ListView只能实现数据纵向滚动的效果,RecyclerView可以说是增强版的List View,不仅可以轻松实现和ListView同样的效果,还优化了ListView的不足之处,目前官方是更加推荐RecyclerView,首先来新建一个RecyclerViewTest项目
首先我们需要在app/build.gradle文件中添加依赖,
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:recyclerview-v7:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
添加完记得Sync Now,接着修改activity_main.xml,
在布局中加入RecyclerView控件是非常简单的,先为RecyclerView指定一个id,然后设置高度和宽度为match_parent,这样会占满整个布局的空间,要注意的是由于RecyclerView并不是内置在系统SDK中的,需要把完整的路径写出来
这里我做的是一个水果的展示,然后建立Fruit.java
package com.example.recyclerviewtest;
public class Fruit {
private String name;
private int imageId;
public Fruit(String name, int imageId){
this.name = name;
this.imageId = imageId;
}
public String getName(){
return name;
}
public int getImageId(){
return imageId;
}
}
接着建立fruit_item.xml
接下来我们需要为RecycleView准备一个适配器,新建FruitAdapter.java,让这个适配器继承RecyclerView.Adapter,并将泛型指定为FruitAdapter.ViewHolder,然后在ViewHolder的构造参数中要传入一个View参数,这个参数通常就是RecyclerView子项的最外层布局,通过findViewById()方法来获取布局中的ImageView和TextView
package com.example.recyclerviewtest;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
public class FruitAdapter extends RecyclerView.Adapter {
private List mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder{
View fruitView;
ImageView fruitImage;
TextView fruitName;
public ViewHolder(View view)
{
super(view);
fruitView = view;
fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
fruitName = (TextView)view.findViewById(R.id.fruit_name);
}
}
// 传入一个构造函数,把数据源传进来,并赋值给全局变量mFruitList
public FruitAdapter(List fruitList){
mFruitList = fruitList;
}
/**
*由于FruitAdapter是继承于RecyclerView.Adapter,那么必须重写onCreateViewHolder()、
*onBindViewHolder()、getItemCount()这3个方法,onCreateViewHolder()用来创建ViewHolder
*实例,然后把fruit_item布局加载进来,创建一个VIewHolder实例,并把加载进来的布局传入到
*构造函数中,最后将ViewHolder实例返回。onBindViewHolder()方法是用来对RecyclerView子
*项中的数据进行赋值,会在每个子项被滚动到屏幕内的时候执行,这里通过positon参数得到当前项
*的Fruit实例,再将数据设置到ViewHolder的ImageView和TextView当中,getItemCount()用来返回
*数据源的长度
**/
@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;
}
@Override
public void onBindViewHolder(ViewHolder holder,int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}
@Override
public int getItemCount(){
return mFruitList.size();
}
}
最后修改MainActivity,在这里用了一个同样的initFruits()方法,用于初始化所有的水果数据,接着在onCreate()方法中获取到RecyclerView实例,然后创建一个LinearLayoutManager对象。LayoutManager用于指定RecyclerView的布局方式,LinearLayoutManager是线性布局的意思,接下来创建FruitAdapter的实例,并将水果数据传入到FruitAdapter的构造函数中,最后调用RecyclerView的setAdapter()方法来完成适配器设置。
package com.example.recyclerviewtest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
private List fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化水果数据
initFruits();
RecyclerView recyclerView = findViewById(R.id.recycler_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.mipmap.ic_launcher);
fruitList.add(apple);
Fruit banner = new Fruit(
("Banner"),R.mipmap.ic_launcher);
fruitList.add(banner);
Fruit pear = new Fruit(
("Pear"),R.mipmap.ic_launcher);
fruitList.add(pear);
Fruit watermalon = new Fruit(
("Watermalon"),R.mipmap.ic_launcher);
fruitList.add(watermalon);
Fruit cherry = new Fruit(
("Cherry"),R.mipmap.ic_launcher);
fruitList.add(cherry);
}
}
}
首先对fruit_item布局进行修改,把元素改为垂直排列
这里要设定宽度,因为文字长度不一的话很难看,使用layout_marginTop属性让文字和图片之间保持距离。
接下来修改MainActivity中的代码,因为LinearLayoutManger.HORIZONTAL是默认纵向排列的,我们要设为横向滚动只需要设置为LinearLayoutManager.HORIZONTAL
package com.example.recyclerviewtest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
private List fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化水果数据
initFruits();
RecyclerView recyclerView = findViewById(R.id.recycler_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.mipmap.ic_launcher);
fruitList.add(apple);
Fruit banner = new Fruit(
("Banner"),R.mipmap.ic_launcher);
fruitList.add(banner);
Fruit pear = new Fruit(
("Pear"),R.mipmap.ic_launcher);
fruitList.add(pear);
Fruit watermalon = new Fruit(
("Watermalon"),R.mipmap.ic_launcher);
fruitList.add(watermalon);
Fruit cherry = new Fruit(
("Cherry"),R.mipmap.ic_launcher);
fruitList.add(cherry);
}
}
}
最后运行一下就可以看到横向布局了
当然,GiridLayoutManager可以用于实现网格布局,StaggeredGirdLayoutManager可以实现瀑布流布局
最后来看看瀑布流布局,首先修改一下fruit_item.xml中的代码
这里我们为了好看把TextView的对齐属性改为居左对齐,因为待会文字会变长
接着来修改MainActivity中的代码
package com.example.recyclerviewtest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
private List fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化水果数据
initFruits();
RecyclerView recyclerView = findViewById(R.id.recycler_view);
/**
*创建StaggeredGridLayoutManager实例,StaggeredGridLayoutManager
*构造函数接收两个参数,第一个参数用于指定布局的列数,表示把布局分为3列,
*第二个参数表示指定布局的排列方向
**/
StaggeredGridLayoutManager layoutManager = new
StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
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.mipmap.ic_launcher);
fruitList.add(apple);
Fruit banner = new Fruit
getRandomLengthName("Banner"),R.mipmap.ic_launcher);
fruitList.add(banner);
Fruit pear = new Fruit(
getRandomLengthName("Pear"),R.mipmap.ic_launcher);
fruitList.add(pear);
Fruit watermalon = new Fruit(
getRandomLengthName("Watermalon"),R.mipmap.ic_launcher);
fruitList.add(watermalon);
Fruit cherry = new Fruit(
getRandomLengthName("Cherry"),R.mipmap.ic_launcher);
fruitList.add(cherry);
}
}
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();
}
因为瀑布流布局需要各个子项高度不一致才能看出明显效果,这里使用getRandLengthName()方法把名字随机重复几遍,这样保证各水果的名字长短不一样
最后运行,可以看到效果
当然,我们还可以加上点击事件,不过要注意的是,RecyclerView并没有提供类似于setOnItemClickListener()这样的注册监听器方法,需要我们自己给子项具体的View去注册点击事件
修改FruitAdapter.java
package com.example.recyclerviewtest;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
public class FruitAdapter extends RecyclerView.Adapter {
private List mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder{
View fruitView;
ImageView fruitImage;
TextView fruitName;
public ViewHolder(View view)
{
super(view);
fruitView = view;
fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
fruitName = (TextView)view.findViewById(R.id.fruit_name);
}
}
public FruitAdapter(List fruitList){
mFruitList = fruitList;
}
@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);
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(),"你点击了文字"+fruit.getName(),
Toast.LENGTH_LONG).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(),"你点击了图片" + fruit.getName(),
Toast.LENGTH_LONG).show();
}
});
// ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder,int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}
@Override
public int getItemCount(){
return mFruitList.size();
}
}
我们在ViewHolder中加入了fruitView变量来保存子项最外层布局的实例,然后在onCreateViewHolder()方法中注册点击事件就可以了