欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

RecyclerView实现瀑布流布局

程序员文章站 2022-06-08 16:28:54
...

RecyclerView实现瀑布流布局




注意:内容来源于郭神《第二行代码》。郭神博客http://blog.csdn.net/guolin_blog

一、RecyclerView是干什么的?


简单点我们可以先把它理解为ListView的一个升级版,因为它不仅可以轻松的完成ListView的各种功能,而且还优化了ListView中存在的各种不足之处。






二、RecyclerView的基本用法

因为Android团队将RecyclerView定义在了support库当中,因此要使用这个控件,我们首先要在项目的build.gradle中添加相应的依赖库才行。

打开app/build.gradle文件,在dependencies闭包下添加如下内容

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:recyclerview-v7:24.2.1'
}

添加完之后要记得点击一下右上方的Sync Now来进行同步。然后就可以在activity_main.xml 中使用它了如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>

这里要注意:因为RecyclerView不是内置在系统的SDK中,所以引用的时候要把完整的包路径写出来




这里我们先用RecyclerView来实现和ListView相同的效果如图所示:

因此这里我们和ListView一样要先准备用来展示的数据: (我们准备在每一个Item上展示一个水果的图片和它的名字即一个ImageView和TextView)

首先先定义一个水果的实体类Fruit,代码如下:

public class Fruit {
    private int imageId;
    private String name;

    public Fruit(int imageId, String name) {
        this.imageId = imageId;
        this.name = name;
    }

    public int getImageId() {
        return imageId;
    }

    public String getName() {
        return name;
    }
}

Fruit类中只有两个字段,name表示水果的名字,imageId表示水果对应图片的资源id。
然后像ListView一样需要为我们的子项指定一个我们自定义的布局,在layout目录下新建fruit-item.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">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_gravity="center_vertical"
        />
</LinearLayout>




这些都准备好了,接下来就需要为 RecyclerView 准备一个适配器了,新建FruitAdapter类,让这个适配器继承自 RecyclerView.Adapter ,并将泛型指定为 FruitAdapter.ViewHolder 。 其中 ViewHolder 是我们在 FruitAdapter 中定义的一个内部类,代码如下所示:

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{

    private List<Fruit> fruits;
    /**
     * 定义内部类 Viewholder 继承 RecyclerView.ViewHolder
     * 这个构造传入的参数 view 就是RecyclerView子项的最外层布局,所以我们就可以通过findViewById()方法来获取布局中的ImageView和TextView的实例了
     */
    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);
        }
    }

    /**
     * 定义一个构造函数 用来把展示的数据传过来 并赋值给一个全局变量fruits
     * @param fruits
     */
    public FruitAdapter(List<Fruit> fruits){
        this.fruits=fruits; 
    }

    // 下面这三个方法都是重写的
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        // 将fruit_item布局加载进来
        View view= LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fruit_item,viewGroup,false);
        //创建ViewHolder实例
        ViewHolder holder=new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int i) {
        //对RecyclerView 的每个子项进行赋值
        Fruit fruit=fruits.get(i);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }

    @Override
    public int getItemCount() {
        //告诉RecyclerView 一共有多少个子项 返回数据源的长度
        return fruits.size();
    }


}




适配器准备好了,下面就可以开始使用RecyclerView了,修改mainActivity.calss中的代码,如下所示:

public class MainActivity extends Activity {

    private List<Fruit> fruits=new ArrayList<Fruit>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init(); //初始化水果数据
        RecyclerView recyclerView= (RecyclerView) findViewById(R.id.recycler_view);
        LinearLayoutManager layoutManager=new LinearLayoutManager(this); //创建LinearLayoutManager 用来指定RecyclerView的布局方式

        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter=new FruitAdapter(fruits);
        recyclerView.setAdapter(adapter);


    }

    private void init() {
        for (int i = 0; i < 2; i++) {
            Fruit apple = new Fruit(R.drawable.apple_pic,"apple");
            fruits.add(apple);
            Fruit banana = new Fruit(R.drawable.banana_pic,"banana");
            fruits.add(banana);
            Fruit orange = new Fruit(R.drawable.orange_pic,"orange");
            fruits.add(orange);
            Fruit watermelon = new Fruit(R.drawable.watermelon_pic, "watermelon");
            fruits.add(watermelon);
            Fruit pear = new Fruit(R.drawable.pear_pic,"pear");
            fruits.add(pear);
            Fruit grape = new Fruit(R.drawable.grape_pic,"grape");
            fruits.add(grape);
            Fruit pineapple = new Fruit(R.drawable.pineapple_pic,"pineapple");
            fruits.add(pineapple);
            Fruit strawberry = new Fruit(R.drawable.strawberry_pic,"strawberry");
            fruits.add(strawberry);
            Fruit cherry = new Fruit(R.drawable.cherry_pic,"cherry");
            fruits.add(cherry);
            Fruit mango = new Fruit(R.drawable.mango_pic,"mango");
            fruits.add(mango);
        }
    }

}

到这里我们就完成了RecyclerView 和ListView 一样的功能了 先运行程序,效果图如下:


RecyclerView实现瀑布流布局




到这里你可能觉得RecyclerView 并没有ListView 方便好用,别急,下面你会看到RecyclerView更强大的功能。




三、实现横向滚动布局




如果你还认为ListView比RecyclerView好用,那么ListView能够实现 横向滚动布局么? 与ListView相比,RecyclerView实现横向滚动非常简单,只需要改动几行代码就可以了

为了节省时间下面我们将在原来的代码上进行改动,首先要对展示每个Item布局的fruit_item.xml 进行修改,因为里面的元素是水平排列的 适合纵向滚动,而如果我们要实现横向滚动的话,应该把水平排列改为垂直排列才比较合理。如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="100dp" android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />

    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_gravity="center_horizontal"
        />
</LinearLayout>

可以看到我们将Linearlayout的布局改为垂直方向排列,并把宽度设为100dp,这里是因为每个图片的文字长度是不一样的,为了美观把wrap_content 改为了100dp。

接下来修改MainActivity中的代码,如下所示:

public class MainActivity extends Activity {

    private List<Fruit> fruits=new ArrayList<Fruit>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init(); //初始化水果数据
        RecyclerView recyclerView= (RecyclerView) findViewById(R.id.recycler_view);
        LinearLayoutManager layoutManager=new LinearLayoutManager(this); //创建LinearLayoutManager 用来指定RecyclerView的布局方式
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); //在这里设置为横向滚动,因为纵向滚动为默认,所以刚才并没有设置
        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter=new FruitAdapter(fruits);
        recyclerView.setAdapter(adapter);


    }
    ......
}

这样我们的横向滚动就完成了,看一下效果图:


RecyclerView实现瀑布流布局




到这里RecyclerView的强大还没有展示出来呢,接下来我们来看一个更强大 的 瀑布流布局:



四、瀑布流布局




首先我们还是先来修改一下fruit_item的代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_margin="5dp" android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />

    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_gravity="left"
        />
</LinearLayout>




接着修改MainActivity的代码:

public class MainActivity extends Activity {

    private List<Fruit> fruits=new ArrayList<Fruit>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init(); //初始化水果数据
        RecyclerView recyclerView= (RecyclerView) findViewById(R.id.recycler_view);
        //这里就不能使用Linearlayout了,要使用RecyclerView 给我们提供的StaggeredGridLayoutManager
        StaggeredGridLayoutManager layoutManager=new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter=new FruitAdapter(fruits);
        recyclerView.setAdapter(adapter);


    }
         //这里因为Fruit名字都是固定的体现不出瀑布流的特点,所以将fruit名字变为随机的长度
         private void init(){
             for (int i = 0; i < 2; i++) {
                 Fruit apple = new Fruit(R.drawable.apple_pic, getRandomLengthName("apple"));
                 fruits.add(apple);
                 Fruit banana = new Fruit(R.drawable.banana_pic, getRandomLengthName("banana"));
                 fruits.add(banana);
                 Fruit orange = new Fruit(R.drawable.orange_pic, getRandomLengthName("orange"));
                 fruits.add(orange);
                 Fruit watermelon = new Fruit(R.drawable.watermelon_pic, getRandomLengthName("watermelon"));
                 fruits.add(watermelon);
                 Fruit pear = new Fruit(R.drawable.pear_pic, getRandomLengthName("pear"));
                 fruits.add(pear);
                 Fruit grape = new Fruit(R.drawable.grape_pic, getRandomLengthName("grape"));
                 fruits.add(grape);
                 Fruit pineapple = new Fruit(R.drawable.pineapple_pic, getRandomLengthName("pineapple"));
                 fruits.add(pineapple);
                 Fruit strawberry = new Fruit(R.drawable.strawberry_pic, getRandomLengthName("strawberry"));
                 fruits.add(strawberry);
                 Fruit cherry = new Fruit(R.drawable.cherry_pic, getRandomLengthName("cherry"));
                 fruits.add(cherry);
                 Fruit mango = new Fruit(R.drawable.mango_pic, getRandomLengthName("mango"));
                 fruits.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实现瀑布流布局